tnblog
首页
视频
资源
登录

Pytorch 新闻分类任务(学习笔记)

2341人阅读 2024/1/4 16:54 总访问:3475631 评论:0 收藏:0 手机
分类: pytorch

Pytorch 新闻分类任务(学习笔记)

目录结构

models文件夹


该文件夹显示搭建的网络结构。
里面有TextCNN.pyTextRNN.py两个文件,对应的网络结构是CNN和RNN,这里我们使用RNN。

THUCNews文件夹


在该文件夹下面有三个文件夹:datalogsaved_dict


data主要是我们的数据。
我们本次要做的一个实验是对一个新闻的一个分类。
首先我们看一下train.txt训练文件数据下的内容。


里面的训练样本格式是:内容+tab+新闻分类的值。
这里一共有10个类别这10个类别记录在我们的class.txt文件中,训练样本一共有18w行数据。
除此之外dev.txt文件和test.txt文件分别代表的我们的验证集和测试集。

那么如何让计算机理解我们的内容呢?


一般我们的做法是不是将内容进行清洗(举例:去掉(图)这种毫无意义的东西)之后,对内功进行分词或者分字,通过对应的语量表做成对应的索引id。


但是这种索引计算机根本不认识,或者说是很死板的认识。
然而Embedding映射表可以解决这样的问题,它是由一些知名的大厂训练出来用于将词或字映射成向量(没有大量的数据是训练不好的)。
词向量矩阵=batch(文本处理大小) max_len(文本长度) E(映射维度)

关于语量表这里准备的文件是vocab.pkl文件,关于embedding准备了腾讯的和搜狗的映射表。

循环递归神经网络 RNN


它主要解决了一个时间类型、文本类型的数据的模型。
如下图所示:


我们可以看到,它仅仅是在普通的神经网络隐藏层中对特征进行再一次的,在又一次学习中既包含了新的特征又包含了旧的特征。
学习举例:如果我们有一个t1的时间数据和t2的时间数据,如果是普通神经网络模型它会将其中都放入同一输入层,二者没有凸显出时间的关系。
当使用RNN,在隐藏层中训练了t1数据,t2进入隐藏层时又回把t1和t2同时进行训练出新的特征。


当我们有很多个时间序列数据时,我们一般只需要保留最后一个全链接层,因为它包含了前面所有的特征。
关于其中产生的中间数据结果,将全部忽略只需要保留最后。

代码示例


我们的主要代码在run.py中。

  1. import time
  2. import torch
  3. import numpy as np
  4. from train_eval import train, init_network
  5. from importlib import import_module
  6. import argparse
  7. from tensorboardX import SummaryWriter
  8. parser = argparse.ArgumentParser(description='Chinese Text Classification')
  9. parser.add_argument('--model', type=str, required=True, help='choose a model: TextCNN, TextRNN, FastText, TextRCNN, TextRNN_Att, DPCNN, Transformer')
  10. parser.add_argument('--embedding', default='pre_trained', type=str, help='random or pre_trained')
  11. parser.add_argument('--word', default=False, type=bool, help='True for word, False for char')
  12. args = parser.parse_args()
  13. if __name__ == '__main__':
  14. dataset = 'THUCNews' # 数据集
  15. # 旋转Embedding
  16. # 搜狗新闻:embedding_SougouNews.npz, 腾讯:embedding_Tencent.npz, 随机初始化:random
  17. embedding = 'embedding_SougouNews.npz'
  18. if args.embedding == 'random':
  19. embedding = 'random'
  20. model_name = args.model #参数model选择模型:TextRNN 可选:TextCNN, TextRNN,
  21. if model_name == 'FastText':
  22. from utils_fasttext import build_dataset, build_iterator, get_time_dif
  23. embedding = 'random'
  24. else:
  25. from utils import build_dataset, build_iterator, get_time_dif
  26. # utils包中用于加载数据集、分词、分字的工具
  27. # 导入模块 models.TextRNN 模块
  28. x = import_module('models.' + model_name)
  29. # 初始化该模块的Config类,进行配置参数
  30. config = x.Config(dataset, embedding)
  31. # 设置随机数的一致性,举例:第一次是3,第二次是6..每次都按照这种进行随机,第一个参数表示初始化值
  32. np.random.seed(1)
  33. torch.manual_seed(1)
  34. torch.cuda.manual_seed_all(1)
  35. torch.backends.cudnn.deterministic = True # 保证每次随机结果一样
  36. # 打印时间
  37. start_time = time.time()
  38. print("Loading data...")
  39. # 创建数据集
  40. vocab, train_data, dev_data, test_data = build_dataset(config, args.word)
  41. train_iter = build_iterator(train_data, config)
  42. dev_iter = build_iterator(dev_data, config)
  43. test_iter = build_iterator(test_data, config)
  44. time_dif = get_time_dif(start_time)
  45. print("Time usage:", time_dif)
  46. # train
  47. config.n_vocab = len(vocab)
  48. # 初始化模型的
  49. model = x.Model(config).to(config.device)
  50. writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))
  51. # 做一下模型初始化
  52. if model_name != 'Transformer':
  53. init_network(model)
  54. print(model.parameters)
  55. # 训练模型
  56. train(config, model, train_iter, dev_iter, test_iter,writer)


TextRNN.py

  1. # coding: UTF-8
  2. import torch
  3. import torch.nn as nn
  4. import torch.nn.functional as F
  5. import numpy as np
  6. class Config(object):
  7. """配置参数"""
  8. def __init__(self, dataset, embedding):
  9. # dataset 文件夹根目录名称
  10. # embedding 映射表的文件名
  11. self.model_name = 'TextRNN'
  12. self.train_path = dataset + '/data/train.txt' # 训练集
  13. self.dev_path = dataset + '/data/dev.txt' # 验证集
  14. self.test_path = dataset + '/data/test.txt' # 测试集
  15. self.class_list = [x.strip() for x in open(
  16. dataset + '/data/class.txt').readlines()] # 类别名单
  17. self.vocab_path = dataset + '/data/vocab.pkl' # 词表
  18. self.save_path = dataset + '/saved_dict/' + self.model_name + '.ckpt' # 模型训练结果
  19. self.log_path = dataset + '/log/' + self.model_name
  20. self.embedding_pretrained = torch.tensor(
  21. np.load(dataset + '/data/' + embedding)["embeddings"].astype('float32'))\
  22. if embedding != 'random' else None # 预训练词向量
  23. self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备
  24. self.dropout = 0.5 # 随机失活,随机丢弃网络中的部分神经元。这里丢弃其中的50%。 (可改)
  25. self.require_improvement = 1000 # 若超过1000batch效果还没提升,则提前结束训练 (提前停止策略)(可改)
  26. self.num_classes = len(self.class_list) # 类别数
  27. self.n_vocab = 0 # 词表大小,在运行时赋值
  28. self.num_epochs = 10 # epoch数 迭代轮数(可改)
  29. self.batch_size = 128 # mini-batch大小(可改)
  30. self.pad_size = 32 # 每句话处理成的长度(短填长切),多退少补
  31. self.learning_rate = 1e-3 # 学习率
  32. self.embed = self.embedding_pretrained.size(1)\
  33. if self.embedding_pretrained is not None else 300 # 字向量维度, 若使用了预训练词向量,则维度统一
  34. self.hidden_size = 128 # lstm隐藏层
  35. self.num_layers = 2 # lstm层数
  36. '''Recurrent Neural Network for Text Classification with Multi-Task Learning'''
  37. class Model(nn.Module):
  38. def __init__(self, config):
  39. super(Model, self).__init__()
  40. # 进行映射向量
  41. if config.embedding_pretrained is not None:
  42. self.embedding = nn.Embedding.from_pretrained(config.embedding_pretrained, freeze=False)
  43. else:
  44. self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1)
  45. # config.embed把每个向量映射到多少个维度
  46. # bidirectional=True 从左往右走后,又从右往左走。维度翻倍256
  47. self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers,
  48. bidirectional=True, batch_first=True, dropout=config.dropout)
  49. # 最后加一个全连接层128*2 2层
  50. self.fc = nn.Linear(config.hidden_size * 2, config.num_classes)
  51. def forward(self, x):
  52. x, _ = x
  53. out = self.embedding(x) # 映射 [batch_size, seq_len, embeding]=[128, 32, 300]
  54. out, _ = self.lstm(out) # LSTM 隐藏层进行训练
  55. out = self.fc(out[:, -1, :]) # 最后全连接层进行训练 句子最后时刻的 hidden state
  56. return out


train_eval.py

  1. # coding: UTF-8
  2. import numpy as np
  3. import torch
  4. import torch.nn as nn
  5. import torch.nn.functional as F
  6. from sklearn import metrics
  7. import time
  8. from utils import get_time_dif
  9. from tensorboardX import SummaryWriter
  10. # 权重初始化,默认xavier
  11. def init_network(model, method='xavier', exclude='embedding', seed=123):
  12. for name, w in model.named_parameters():
  13. if exclude not in name:
  14. if 'weight' in name:
  15. if method == 'xavier':
  16. nn.init.xavier_normal_(w)
  17. elif method == 'kaiming':
  18. nn.init.kaiming_normal_(w)
  19. else:
  20. nn.init.normal_(w)
  21. elif 'bias' in name:
  22. nn.init.constant_(w, 0)
  23. else:
  24. pass
  25. def train(config, model, train_iter, dev_iter, test_iter,writer):
  26. start_time = time.time()
  27. # 设置训练模式
  28. model.train()
  29. # Adam训练模型 lr配置学习率
  30. optimizer = torch.optim.Adam(model.parameters(), lr=config.learning_rate)
  31. # 学习率指数衰减,每次epoch:学习率 = gamma * 学习率
  32. # scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
  33. total_batch = 0 # 记录进行到多少batch
  34. dev_best_loss = float('inf')
  35. last_improve = 0 # 记录上次验证集loss下降的batch数
  36. flag = False # 记录是否很久没有效果提升
  37. #writer = SummaryWriter(log_dir=config.log_path + '/' + time.strftime('%m-%d_%H.%M', time.localtime()))
  38. for epoch in range(config.num_epochs):
  39. print('Epoch [{}/{}]'.format(epoch + 1, config.num_epochs))
  40. # scheduler.step() # 学习率衰减
  41. for i, (trains, labels) in enumerate(train_iter):
  42. #print (trains[0].shape)
  43. # 前向传播
  44. outputs = model(trains)
  45. # 梯度清0
  46. model.zero_grad()
  47. # 损失函数
  48. loss = F.cross_entropy(outputs, labels)
  49. # 参数更新
  50. loss.backward()
  51. optimizer.step()
  52. # 每执行一定的epoch我们执行一下验证集
  53. if total_batch % 100 == 0:
  54. # 每多少轮输出在训练集和验证集上的效果
  55. # 获取标签真实值
  56. true = labels.data.cpu()
  57. # 预测值
  58. predic = torch.max(outputs.data, 1)[1].cpu()
  59. # 计算准确率
  60. train_acc = metrics.accuracy_score(true, predic)
  61. dev_acc, dev_loss = evaluate(config, model, dev_iter)
  62. # 判断当前损失相对于上一次如果要小,则保存模型
  63. if dev_loss < dev_best_loss:
  64. dev_best_loss = dev_loss
  65. torch.save(model.state_dict(), config.save_path)
  66. improve = '*'
  67. last_improve = total_batch
  68. else:
  69. improve = ''
  70. time_dif = get_time_dif(start_time)
  71. # 打印结果
  72. msg = 'Iter: {0:>6}, Train Loss: {1:>5.2}, Train Acc: {2:>6.2%}, Val Loss: {3:>5.2}, Val Acc: {4:>6.2%}, Time: {5} {6}'
  73. print(msg.format(total_batch, loss.item(), train_acc, dev_loss, dev_acc, time_dif, improve))
  74. writer.add_scalar("loss/train", loss.item(), total_batch)
  75. writer.add_scalar("loss/dev", dev_loss, total_batch)
  76. writer.add_scalar("acc/train", train_acc, total_batch)
  77. writer.add_scalar("acc/dev", dev_acc, total_batch)
  78. # 又调整会训练模式中
  79. model.train()
  80. total_batch += 1
  81. # 如果当前次数比上一次最好的大于我们设定的1000次容忍度,就结束
  82. if total_batch - last_improve > config.require_improvement:
  83. # 验证集loss超过1000batch没下降,结束训练
  84. print("No optimization for a long time, auto-stopping...")
  85. flag = True
  86. break
  87. if flag:
  88. break
  89. writer.close()
  90. # 选择最好的一次,调用测试集
  91. test(config, model, test_iter)
  92. def test(config, model, test_iter):
  93. # test
  94. model.load_state_dict(torch.load(config.save_path))
  95. model.eval()
  96. start_time = time.time()
  97. test_acc, test_loss, test_report, test_confusion = evaluate(config, model, test_iter, test=True)
  98. msg = 'Test Loss: {0:>5.2}, Test Acc: {1:>6.2%}'
  99. print(msg.format(test_loss, test_acc))
  100. print("Precision, Recall and F1-Score...")
  101. print(test_report)
  102. print("Confusion Matrix...")
  103. print(test_confusion)
  104. time_dif = get_time_dif(start_time)
  105. print("Time usage:", time_dif)
  106. def evaluate(config, model, data_iter, test=False):
  107. # 跳到验证集
  108. model.eval()
  109. loss_total = 0
  110. predict_all = np.array([], dtype=int) # 预测的结果
  111. labels_all = np.array([], dtype=int) # 正确的结果
  112. with torch.no_grad():
  113. for texts, labels in data_iter:
  114. outputs = model(texts)
  115. # 计算损失
  116. loss = F.cross_entropy(outputs, labels)
  117. loss_total += loss
  118. labels = labels.data.cpu().numpy()
  119. predic = torch.max(outputs.data, 1)[1].cpu().numpy()
  120. # 获取所有的验证集的真实值和预测值
  121. labels_all = np.append(labels_all, labels)
  122. predict_all = np.append(predict_all, predic)
  123. # 正确率
  124. acc = metrics.accuracy_score(labels_all, predict_all)
  125. # 如果我们在执行测试,它有一些评估指标
  126. if test:
  127. report = metrics.classification_report(labels_all, predict_all, target_names=config.class_list, digits=4)
  128. confusion = metrics.confusion_matrix(labels_all, predict_all)
  129. return acc, loss_total / len(data_iter), report, confusion
  130. return acc, loss_total / len(data_iter)


utils.py

  1. # coding: UTF-8
  2. import os
  3. import torch
  4. import numpy as np
  5. import pickle as pkl
  6. from tqdm import tqdm
  7. import time
  8. from datetime import timedelta
  9. MAX_VOCAB_SIZE = 10000 # 词表长度限制
  10. UNK, PAD = '<UNK>', '<PAD>' # 未知字,padding符号
  11. def build_vocab(file_path, tokenizer, max_size, min_freq):
  12. vocab_dic = {}
  13. with open(file_path, 'r', encoding='UTF-8') as f:
  14. for line in tqdm(f):
  15. lin = line.strip()
  16. if not lin:
  17. continue
  18. content = lin.split('\t')[0]
  19. for word in tokenizer(content):
  20. vocab_dic[word] = vocab_dic.get(word, 0) + 1
  21. vocab_list = sorted([_ for _ in vocab_dic.items() if _[1] >= min_freq], key=lambda x: x[1], reverse=True)[:max_size]
  22. vocab_dic = {word_count[0]: idx for idx, word_count in enumerate(vocab_list)}
  23. vocab_dic.update({UNK: len(vocab_dic), PAD: len(vocab_dic) + 1})
  24. return vocab_dic
  25. def build_dataset(config, ues_word):
  26. if ues_word:
  27. tokenizer = lambda x: x.split(' ') # 以空格隔开,word-level 定义分词器
  28. else:
  29. tokenizer = lambda x: [y for y in x] # char-level 定义分字器
  30. # 加载语量表,词汇表(没有就根据训练集进行创建一个)
  31. if os.path.exists(config.vocab_path):
  32. vocab = pkl.load(open(config.vocab_path, 'rb'))
  33. else:
  34. vocab = build_vocab(config.train_path, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
  35. pkl.dump(vocab, open(config.vocab_path, 'wb'))
  36. print(f"Vocab size: {len(vocab)}") # 4762个
  37. def load_dataset(path, pad_size=32):
  38. contents = []
  39. # 读取文本数据
  40. with open(path, 'r', encoding='UTF-8') as f:
  41. # 遍历每一行
  42. for line in tqdm(f):
  43. # 去掉换行符
  44. lin = line.strip()
  45. if not lin:
  46. continue
  47. # 分句得出句子和标签
  48. content, label = lin.split('\t')
  49. words_line = []
  50. # 分字
  51. token = tokenizer(content)
  52. # 获取分字长度
  53. seq_len = len(token)
  54. # 判断超过我这里是10的长度的按照<PAD>补齐
  55. if pad_size:
  56. if len(token) < pad_size:
  57. token.extend([vocab.get(PAD)] * (pad_size - len(token)))
  58. else:
  59. token = token[:pad_size]
  60. seq_len = pad_size
  61. # word to id
  62. for word in token:
  63. # 将字转换成语量表的索引id添加到words_line中,如果找不到用<UNK>代替
  64. words_line.append(vocab.get(word, vocab.get(UNK)))
  65. contents.append((words_line, int(label), seq_len))
  66. # 返回语量表、标签与长度
  67. return contents # [([...], 0), ([...], 1), ...]
  68. # 加载训练集、验证集和测试集 参数:路径,分字。
  69. train = load_dataset(config.train_path, config.pad_size)
  70. dev = load_dataset(config.dev_path, config.pad_size)
  71. test = load_dataset(config.test_path, config.pad_size)
  72. # 返回语量表,训练集、验证集和测试集
  73. return vocab, train, dev, test
  74. class DatasetIterater(object):
  75. def __init__(self, batches, batch_size, device):
  76. self.batch_size = batch_size
  77. self.batches = batches
  78. self.n_batches = len(batches) // batch_size
  79. self.residue = False # 记录batch数量是否为整数
  80. # 判断能否整除
  81. if len(batches) % self.n_batches != 0:
  82. self.residue = True
  83. self.index = 0
  84. # 设置跑的设备
  85. self.device = device
  86. def _to_tensor(self, datas):
  87. x = torch.LongTensor([_[0] for _ in datas]).to(self.device)
  88. y = torch.LongTensor([_[1] for _ in datas]).to(self.device)
  89. # pad前的长度(超过pad_size的设为pad_size)
  90. seq_len = torch.LongTensor([_[2] for _ in datas]).to(self.device)
  91. return (x, seq_len), y
  92. def __next__(self):
  93. if self.residue and self.index == self.n_batches:
  94. batches = self.batches[self.index * self.batch_size: len(self.batches)]
  95. self.index += 1
  96. batches = self._to_tensor(batches)
  97. return batches
  98. elif self.index > self.n_batches:
  99. self.index = 0
  100. raise StopIteration
  101. else:
  102. batches = self.batches[self.index * self.batch_size: (self.index + 1) * self.batch_size]
  103. self.index += 1
  104. batches = self._to_tensor(batches)
  105. return batches
  106. def __iter__(self):
  107. return self
  108. def __len__(self):
  109. if self.residue:
  110. return self.n_batches + 1
  111. else:
  112. return self.n_batches
  113. def build_iterator(dataset, config):
  114. iter = DatasetIterater(dataset, config.batch_size, config.device)
  115. return iter
  116. def get_time_dif(start_time):
  117. """获取已使用时间"""
  118. end_time = time.time()
  119. time_dif = end_time - start_time
  120. return timedelta(seconds=int(round(time_dif)))
  121. if __name__ == "__main__":
  122. '''提取预训练词向量'''
  123. # 下面的目录、文件名按需更改。
  124. train_dir = "./THUCNews/data/train.txt"
  125. vocab_dir = "./THUCNews/data/vocab.pkl"
  126. pretrain_dir = "./THUCNews/data/sgns.sogou.char"
  127. emb_dim = 300
  128. filename_trimmed_dir = "./THUCNews/data/embedding_SougouNews"
  129. if os.path.exists(vocab_dir):
  130. word_to_id = pkl.load(open(vocab_dir, 'rb'))
  131. else:
  132. # tokenizer = lambda x: x.split(' ') # 以词为单位构建词表(数据集中词之间以空格隔开)
  133. tokenizer = lambda x: [y for y in x] # 以字为单位构建词表
  134. word_to_id = build_vocab(train_dir, tokenizer=tokenizer, max_size=MAX_VOCAB_SIZE, min_freq=1)
  135. pkl.dump(word_to_id, open(vocab_dir, 'wb'))
  136. embeddings = np.random.rand(len(word_to_id), emb_dim)
  137. f = open(pretrain_dir, "r", encoding='UTF-8')
  138. for i, line in enumerate(f.readlines()):
  139. # if i == 0: # 若第一行是标题,则跳过
  140. # continue
  141. lin = line.strip().split(" ")
  142. if lin[0] in word_to_id:
  143. idx = word_to_id[lin[0]]
  144. emb = [float(x) for x in lin[1:301]]
  145. embeddings[idx] = np.asarray(emb, dtype='float32')
  146. f.close()
  147. np.savez_compressed(filename_trimmed_dir, embeddings=embeddings)

注意我们在使用vscode跑时需要在launch.json中加上model参数。

  1. {
  2. "name": "Python: 当前文件",
  3. "type": "python",
  4. "request": "launch",
  5. "program": "${file}",
  6. "console": "integratedTerminal",
  7. "justMyCode": true,
  8. "args": [
  9. "--model","TextRNN"
  10. ]
  11. },


代码链接


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

Pytorch 初探

Pytorch 初探[TOC] Pytorch简介PyTorch由 Facebook 的 AI 研究团队开发的一个开源的机器学习库,它提供了张量(tensor)计...

Pytorch 自动求导与简单的线性回归

Pytorch 自动求导与简单的线性回归[TOC] 环境安装安装pytorch%pip install torch torchvision torchaudio 自动计算反向...

Pytorch Tensor 常见的形式

Pytorch Tensor 常见的形式[TOC] 值 描述 scalar 0维张量 vector 1维张量 matrix 2维张量 ...

Pytorch 气温预测

Pytorch 气温预测[TOC] 准备数据集下载temps.csv数据集。# 下载包 !wget https://raw.githubusercontent.com/AiDaShi/lea...

Pytorch Mnist分类任务

Pytorch Mnist分类任务[TOC] Mnist分类任务了解目标——网络基本构建与训练方法,常用函数解析——torch.nn.functional...

Pytorch 卷积神经网络效果

Pytorch 卷积神经网络效果[TOC] 数据与在线实践数据链接: https://pan.baidu.com/s/1VkrHDZGukkF900zLncMn5g 密码: 3lom...

Pytorch 基于经典网络架构训练图像分类模型

Pytorch 基于经典网络架构训练图像分类模型[TOC] 数据预处理部分:数据增强:torchvision中transforms模块自带功能,比较...

Pytorch 卷积神经网络效果

Pytorch 卷积神经网络效果[TOC] 数据集Dataloader制作如何自定义数据集:1.数据和标签的目录结构先搞定(得知道到哪读数据)...

Pytorch Flask服务部署图片识别学习笔记

Pytorch Flask服务部署图片识别(学习笔记)[TOC] Flask 简介Flask是一个用Python编写的轻量级Web应用框架。它简单易用,...

Pytorch 预测产量易化学习笔记

Pytorch 预测产量(易化学习笔记一)[TOC] 实验目的(二维)通过温度进行产量预测。 实验代码导入数据集import torch im...

Pytorch 曲线拟合易化学习笔记

Pytorch 曲线拟合(易化学习笔记二)[TOC] 感染与天数预测import matplotlib.pyplot as plt import torch import torch....

Pytorch 识别手写数字易化学习笔记

Pytorch 识别手写数字(易化学习笔记三)[TOC] 识别手写数字LeNet-5手写数字识别的非常高效的卷积神经网络。高效原因:1....

Pytorch cifar10识别普适物体易化学习笔记

Pytorch cifar10识别普适物体(易化学习笔记四)[TOC] CIFAR-10简介CIFAR-10(Canadian Institute For Advanced Research...

Pytorch loguru日志收集易化学习笔记

Pytorch loguru日志收集(易化学习笔记五)[TOC] loguru日志简介Loguru 是一个 Python 日志库,旨在简化日志记录的设置和...

Pytorch TensorBoard运用易化学习笔记

Pytorch TensorBoard运用(易化学习笔记六)[TOC] TensorBoard简介TensorBoard是TensorFlow的可视化工具包,旨在帮助研究...
这一世以无限游戏为使命!
排名
2
文章
636
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术