Pytorch官方文档:https://pytorch.org/docs/stable/torch.html?

1. 写在前面

今天开始,兼顾Pytorch学习, 如果刚刚接触深度学习并且想快速搭建神经网络完成任务享受快感,当然是Keras框架首选,但是如果想在深度学习或人工智能这条路上走的更远,只有Keras就显得有点独木难支,这时候我们需要一个更加强大的框架,这里我想学习Pytorch,它代码通俗易懂,接近Python原生,学起来也容易一些,所以接下来会整理自己在快速入门Pytorch道路上的所见所得,这个系列会有8篇理论+实战的文章,也是我正在学习的B站上的Pytorch入门实战课程,我会把学习过程的笔记和所思所想整理下来,也希望能帮助更多的人进军Pytorch。想要快速学习Pytorch,最好的秘诀就是手握官方文档,然后不断的实战加反思

如果想真正的理解知识,那么最好的方式就是用自己的话再去描述一遍, 通过这个系列,我相信能够打开Pytorch的大门,去眺望一个新的世界。

今天是课程的第四节课的内容, 用Pytorch实现三个模型来做情感分析(检测一段文字的情感是正面还是负面的), 既然是情感分析任务, 所以这节课依然会有很多Pytorch代码, 我觉得重点应该放在那三个模型上, 分别是Word Averaging模型, RNN/LSTM模型和CNN模型, 因为学习知识是要学会迁移学习的一种思想, 这三种模型或许不仅适合于情感分类任务, 而且可能会迁移到别的任务上去, 所以这节课既是学习Pytorch的一些知识, 也是整理和积累一些常用的模型以及它们的Pytorch实现方法。

这节课的逻辑是这样, 我们围绕着一个情感分类的任务进行展开, 即输入一段话, 判断是积极情感还是消极情感, 比较简单的那种, 数据用的是IMDB影评数据集, 首先,就是这个数据集的准备, 这个依然是用的torchtext工具包来完成, 并且帮助我们来创建一个词典。 准备好了数据之后, 就是搭建模型, 然后进行预测的工作。 这部分, 就是用Pytorch实现三个模型, 我会重点分析一下这三个模型的实现细节并在代码中做出一些注释, 方便以后的迁移使用。 最后的模型训练部分, 这次是把训练和验证写成了一种函数的方式, 我觉得这种写法非常好, 以后在写Pytorch代码的时候也可以借鉴借鉴。

大纲如下

  • 数据的准备
  • 模型的建立和训练

Ok, let’s go!

2. 数据的准备

数据的准备部分这里用的torchtext这个工具包, 这个工具包在前面那节课其实就已经见识过, 这里和上面的使用基本一致, 不过有了一些新的东西。

首先, 我们还是先导入一些包并固定一些随机种子:

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchtext import data
import torch.optim as optim
import timeSEED = 1234torch.manual_seed(SEED)
torch.cuda.manual_seed(SEED)
torch.backends.cudnn.deterministic = True

准备数据分为下面几个步骤:

  1. 下载数据集
    下载IMDb数据集,然后分成train/test两个torchtext.datasets类别。数据被Fields处理。首先再解释一下Field, TorchText中的一个重要概念是FieldField决定了你的数据会被怎样处理。在我们的情感分类任务中,我们所需要接触到的数据有文本字符串和两种情感,“pos"或者"neg”。 Field的参数制定了数据会被怎样处理。我们使用TEXT field来定义如何处理电影评论,使用LABEL field来处理两个情感类别。

    TEXT = data.Field(tokenize='spacy')
    LABEL = data.LabelField(dtype=torch.float)
    

    我们的TEXT field带有tokenize='spacy',这表示我们会用spaCy tokenizer来tokenize英文句子。如果我们不特别声明tokenize这个参数,那么默认的分词方法是使用空格。所以如果没有这个包, 需要先安装spaCy这个包

    pip install -U spacy
    python -m spacy download en
    

    如果是Windows系统, 这个的执行最好是在管理员的身份下运行窗口, 然后输入这两句代码。下面是下载数据集:

    train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)
    print(f'Number of training examples: {len(train_data)}')
    print(f'Number of testing examples: {len(test_data)}')# 结果:
    Number of training examples: 25000
    Number of testing examples: 25000
    

    IMDb数据集一共有50000电影评论,每个评论都被标注为正面的或负面的。可以看一下其中的一个example长啥样:

    print(vars(train_data.examples[0]))
    

    结果如下:

  2. 划分数据集
    由于我们现在只有train/test这两个分类,所以我们需要创建一个新的validation set。我们可以使用.split()创建新的分类。默认的数据分割是 70、30,如果我们声明split_ratio,可以改变split之间的比例,split_ratio=0.8表示80%的数据是训练集,20%是验证集。我们还声明random_state这个参数,确保我们每次分割的数据集都是一样的。

    train_data, valid_data = train_data.split(random_state=random.seed(SEED))
    print(f'Number of training examples: {len(train_data)}')
    print(f'Number of validation examples: {len(valid_data)}')
    print(f'Number of testing examples: {len(test_data)}')## 结果:
    Number of training examples: 17500
    Number of validation examples: 7500
    Number of testing examples: 25000
    
  3. 创建词典
    vocabulary 就是把每个单词一一映射到一个数字。我们使用最常见的25k个单词来构建我们的单词表,用max_size这个参数可以做到这一点。所有其他的单词都用<unk>来表示。 当然这里采用了一种预训练, 用的是预训练好的glove向量。

    TEXT.build_vocab(train_data, max_size=25000, vectors="glove.6B.100d", unk_init=torch.Tensor.normal_)
    LABEL.build_vocab(train_data)print(f"Unique tokens in TEXT vocabulary: {len(TEXT.vocab)}")  # 25002
    print(f"Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}")  # 2
    

    创建完了词典之后, 我们可以直接用 stoi(string to int) 或者 itos (int to string) 来查看我们的单词表。

    print(TEXT.vocab.itos[:10])  # ['<unk>', '<pad>', 'the', ',', '.', 'and', 'a', 'of', 'to', 'is']
    print(LABEL.vocab.stoi)  # defaultdict(None, {'neg': 0, 'pos': 1})

    当我们把句子传进模型的时候,我们是按照一个个 batch 传进去的,也就是说,我们一次传入了好几个句子,而且每个batch中的句子必须是相同的长度。为了确保句子的长度相同,TorchText会把短的句子pad到和最长的句子等长。

  4. 创建iterators
    每个itartion都会返回一个batch的examples。我们会使用BucketIteratorBucketIterator会把长度差不多的句子放到同一个batch中,确保每个batch中不出现太多的padding。严格来说,我们这份notebook中的模型代码都有一个问题,也就是我们把<pad>也当做了模型的输入进行训练。更好的做法是在模型中把由<pad>产生的输出给消除掉。在这节课中我们简单处理,直接把<pad>也用作模型输入了。由于<pad>数量不多,模型的效果也不差。如果我们有GPU,还可以指定每个iteration返回的tensor都在GPU上。

    BATCH_SIZE = 64device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    # 一句话就可以搞定Iterator的建立
    train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits((train_data, valid_data, test_data), batch_size=BATCH_SIZE,device=device)
    # 这行代码可以看一个样本到底长啥样, 在Iterator里面,每个单词都用词典中的位置代替了, 每一列是一个样本
    [TEXT.vocab.itos[i] for i in next(iter(train_iterator)).text[1, :]]
    

这样就把数据集给准备好了, 下面就是搭建模型的过程。 也是重头戏了吧,主要是看看这些模型长啥样, 然后怎么用。

3. 模型的建立和训练

3.1 Word Averaging 模型

我们首先介绍一个简单的Word Averaging模型。这个模型非常简单,我们把每个单词都通过Embedding层投射成word embedding vector,然后把一句话中的所有word vector做个平均,就是整个句子的vector表示了。接下来把这个sentence vector传入一个Linear层,做分类即可。

所以这个网络的前向传播是这样子的, 首先是输入text, 也就是上面准备好的数据的其中一个Iterator, 大小是[seq_len, batch_size], 接下来通过一个embedding层, 就会得到每个单词的embedding向量, 这个矩阵的大小就是[seq_len, batch_size, embed_dim], 这时候我们把前两个维度换一下, [batch_size, seq_len, embed_dim], 接下来就是在句子的维度进行求平均, 也就是把句子长度的那个维度压扁, 我们这里采用的是avg_pool2d来做average pooling, avg_pool2d的kernel size是 (embedded.shape[1], 1),所以句子长度的那个维度会被压扁。这个地方需要理解一下, 经过这个操作之后, 矩阵的维度变成了[batch_size, 1, embed_dim], 就是seq_len的维度上进行了一个求平均, 这样就得到了一句话的embedding。 然后通过全连接层得到最后的输出结果, 所以这个网络还是比较简单的。

class WordAVGModel(nn.Module):def __init__(self, vocab_size, embedding_dim, output_dim, pad_idx):super().__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=pad_idx)self.fc = nn.Linear(embedding_dim, output_dim)def forward(self, text):embedded = self.embedding(text) # [sent len, batch size, emb dim]embedded = embedded.permute(1, 0, 2) # [batch size, sent len, emb dim]pooled = F.avg_pool2d(embedded, (embedded.shape[1], 1)).squeeze(1) # [batch size, embedding_dim]# 这个就相当于在seq_len维度上做了一个平均return self.fc(pooled)

这里还发现一个用Pytorch搭建神经网络的技巧或者是习惯, 就是先把大框架搭好:

class WordAVGModel(nn.Module):def __init__(self, ):passdef forward(self, text):passdef .....

先把这个框架搭好, 然后再去写forward函数, 因为这个是网络的计算过程, 然后再写初始化的部分, 因为可能一上来不知道网络里面到底应该有哪些网络层, 先写前向传播之后, 就有利于知道了需要定义哪些层, 这时候再写init的时候就好写了, 最后再定义__init__里面的形参, 这个参考__init__的成员里面用到了哪些需要外界传递的参数, 有种从下往上写的感觉。

搭建完了网络模型之后, 就可以定义一些参数, 然后建立这个网络:

INPUT_DIM = len(TEXT.vocab)
EMBEDDING_DIM = 100
OUTPUT_DIM = 1
PAD_IDX = TEXT.vocab.stoi[TEXT.pad_token]model = WordAVGModel(INPUT_DIM, EMBEDDING_DIM, OUTPUT_DIM, PAD_IDX)

下面应该就是网络的训练部分了, 但是这个任务里面又给出了一个embedding向量的初始化技巧, 采用了已经训练好的embedding向量进行一个初始化(glove), 这样就相当于网络训练的时候, embedding这部分只需要简单的微调就可以, 可以加速训练, 所以这里就把训练好的glove的参数放到了embedding层的w上: 也类似于一种迁移思想

pretrained_embeddings = TEXT.vocab.vectors
model.embedding.weight.data.copy_(pretrained_embeddings)# 相当于把embedding向量的w参数初始化成了通过大量语句训练好的embedding, 这样网络训练的时候向量只需微调# 当然那两个特殊字符, 我们还是初始化为0
UNK_IDX = TEXT.vocab.stoi[TEXT.unk_token]
model.embedding.weight.data[UNK_IDX] = torch.zeros(EMBEDDING_DIM)
model.embedding.weight.data[PAD_IDX] = torch.zeros(EMBEDDING_DIM)

下面开始训练, 这次训练是是事先写好了训练和验证函数, 所以这个写法可以借鉴一下:

def train(model, iterator, optimizer, criterion):epoch_loss = 0epoch_acc = 0model.train()for batch in iterator:optimizer.zero_grad()predictions = model(batch.text).squeeze(1)loss = criterion(predictions, batch.label)acc = binary_accuracy(predictions, batch.label)loss.backward()optimizer.step()epoch_loss += loss.item()epoch_acc += acc.item()return epoch_loss / len(iterator), epoch_acc / len(iterator)def evaluate(model, iterator, criterion):epoch_loss = 0epoch_acc = 0model.eval()with torch.no_grad():for batch in iterator:predictions = model(batch.text).squeeze(1)loss = criterion(predictions, batch.label)acc = binary_accuracy(predictions, batch.label)epoch_loss += loss.item()epoch_acc += acc.item()return epoch_loss / len(iterator), epoch_acc / len(iterator)

这样写的好处就是, 如果换了模型, 训练的函数不用改,下面再加两个辅助函数, 一个是计算acc的, 一个是计算运行时间的:

def binary_accuracy(preds, y):"""Returns accuracy per batch, i.e. if you get 8/10 right, this returns 0.8, NOT 8"""#round predictions to the closest integerrounded_preds = torch.round(torch.sigmoid(preds))correct = (rounded_preds == y).float() #convert into float for divisionacc = correct.sum()/len(correct)return accdef epoch_time(start_time, end_time):elapsed_time = end_time - start_timeelapsed_mins = int(elapsed_time / 60)elapsed_secs = int(elapsed_time - (elapsed_mins * 60))return elapsed_mins, elapsed_secs

下面开始正式的训练:

optimizer = optim.Adam(model.parameters())
criterion = nn.BCEWithLogitsLoss()   # 这个是加了sigmoid的损失函数
model = model.to(device)
criterion = criterion.to(device)N_EPOCHS = 10best_valid_loss = float('inf')for epoch in range(N_EPOCHS):start_time = time.time()train_loss, train_acc = train(model, train_iterator, optimizer, criterion)valid_loss, valid_acc = evaluate(model, valid_iterator, criterion)end_time = time.time()epoch_mins, epoch_secs = epoch_time(start_time, end_time)if valid_loss < best_valid_loss:best_valid_loss = valid_losstorch.save(model.state_dict(), 'wordavg-model.pt')print(f'Epoch: {epoch+1:02} | Epoch Time: {epoch_mins}m {epoch_secs}s')print(f'\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc*100:.2f}%')print(f'\t Val. Loss: {valid_loss:.3f} |  Val. Acc: {valid_acc*100:.2f}%')

这个训练函数的写法我感觉不错, 其实后面的RNN模型, CNN模型, 都是同样的训练代码, 无非就是model变了一下, 所以这种写法需要借鉴一下。 训练结果是这样的:

这种显示方式也是不错的, 这样能看到我们的模型是不是正常工作。 下面是对模型的测试:

model.load_state_dict(torch.load('wordavg-model.pt'))
test_loss, test_acc = evaluate(model, test_iterator, criterion)
print(f'Test Loss: {test_loss:.3f} | Test Acc: {test_acc*100:.2f}%')## Test Loss: 0.416 | Test Acc: 84.41%

这里又看到了模型的保存与导入方式, Word Averaging模型的表现整体上来说还是可以的。 我们可以实际测一测:

import spacy
nlp = spacy.load('en')def predict_sentiment(sentence):tokenized = [tok.text for tok in nlp.tokenizer(sentence)]indexed = [TEXT.vocab.stoi[t] for t in tokenized]tensor = torch.LongTensor(indexed).to(device)tensor = tensor.unsqueeze(1)prediction = torch.sigmoid(model(tensor))return prediction.item()predict_sentiment("This film is terrible")   # 1.0124620496917103e-25
predict_sentiment("This film is great")  # 1

哈哈, 还是挺有意思的。

3.2 RNN Model

下面我们尝试把模型换成一个recurrent neural network (RNN)。RNN经常会被用来encode一个sequence
ht=RNN(xt,ht−1)h_t = \text{RNN}(x_t, h_{t-1})ht=RNN(xt,ht1)

  • 我们使用最后一个hidden state hTh_ThT来表示整个句子。
  • 然后我们把hTh_ThT通过一个线性变换fff,然后用来预测句子的情感。

这里会使用一个2层的双向LSTM网络:

网络的计算过程是这样的, 依然我们的输入是一批句子, 大小是[seq_len, batch_size], 第一步依然是经过一个embedding层得到每个单词的embedding向量, 这时候维度就是[seq_len, batch_size, embed_dim], 然后是经过一个双向的LSTM, 并且是2层堆叠起来的, 这时候的网络输出会是一个[seq_len, batch_size, hidden_size*num_directions], LSTM的隐藏状态h和c是[num_layers*num_directions, batch_size, hidden_size], 所以这时候我们需要拿到最后一层最后一个时间步LSTM的隐藏层状态, 把他俩进行一个拼接, 然后再通过全连接层得到结果。所以总体代码是这样:

class RNN(nn.Module):def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim, n_layers, bidirectional, dropout, pad_idx):super().__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=pad_idx)self.rnn = nn.LSTM(embedding_dim, hidden_dim, num_layers=n_layers, bidirectional=bidirectional, dropout=dropout)self.fc = nn.Linear(hidden_dim*2, output_dim)self.dropout = nn.Dropout(dropout)def forward(self, text):embedded = self.dropout(self.embedding(text)) #[sent len, batch size, emb dim]output, (hidden, cell) = self.rnn(embedded)#output = [sent len, batch size, hid dim * num directions]#hidden = [num layers * num directions, batch size, hid dim]#cell = [num layers * num directions, batch size, hid dim]#concat the final forward (hidden[-2,:,:]) and backward (hidden[-1,:,:]) hidden layershidden = self.dropout(torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim=1)) # [batch size, hid dim * num directions]#and apply dropoutreturn self.fc(hidden.squeeze(0))

写前向传播的时候, 标注一下每一层之后变量的维度变化, 也是一个好的习惯。 后面的训练代码, 其实和上面的基本就一致了, 这就就不再写了。看一下双向LSTM的表现:

model.load_state_dict(torch.load('lstm-model.pt'))
test_loss, test_acc = evaluate(model, test_iterator, criterion)
print(f'Test Loss: {test_loss:.3f} | Test Acc: {test_acc*100:.2f}%')## Test Loss: 0.377 | Test Acc: 82.91%

3.3 CNN Model

这个倒是见到了一个新的思路, 没想到CNN也可以处理语言序列, 并且效果还不错, 所以这个是这次get到的比较大的一个收获吧。

卷积神经网络的计算过程相比于前面的两个网络模型有点难理解, 因为我们知道CNN一般是用于处理图像的, 而这里的语言模型是时序数据, CNN如何捕捉时序序列之间的关联呢? 这里用的利用的当然是卷积+池化的操作, 不过这次用的卷积核竟然不是正方形的, 长见识了。这个网络结构来自于:【Convolutional Neural Networks for Setence Classification】

前向传播的过程是这样, 首先还是接受了一批句子, 维度是[batch_size, seq_len], 注意这里先转换了一下维度, 然后经过embedding层, 得到[batch_size, seq_len, emb_dim], 当然我们知道2维卷积接收的输入是4维的, 因为要把这个东西看成个图像才能进行二维卷积, 二维卷积层接收的输入是[batch_size, in_chnnels, Height, Width], 而我们的embedding之后是三维, 所以需要再第二个维度扩出一个1来,表示通道数是1维,后面的seq_len和emb_dim表示图像的长和宽, 我们下一步在这里做卷积。 卷积核的大小是[filter_size, emb_dim], 第一次见这样的代码, 之前以为卷积核都是正方形的那种,这样对[seq_len, emb_dim]进行卷积之后, 就会把emb_dim这个维度给变成1, 提取了每个单词之间的特征, 这时候输出维度是[batch_size, num_filters, seq_len-filter_size+1, 1], 这个维度可能比较难理解一下, 如果理解了卷积的操作原理,其实也不难理解, 这次卷积就是在embedding向量之后的后两维上进行卷积提取单词之间的特征, 无非就是卷积核的第二个维度是emb_dim, 卷积的时候把每个单词全部的词向量都进行了运算, 因为考虑了全部的词向量之后才是一个完整的单词嘛! 至于第一个维度的filter_size, 就是我们之前见的那种了, 表示我们一次考虑多少个单词之间的关系, 这样就确定出了后两个维度, 而第二个维度是过滤器的个数, 这个查阅官方文档看2维卷积的输出就可以理解了。 得到上面的这个向量, 然后把最后一个维度去掉, 然后在seq_len-filter_size+1这个维度上进行最大池化, 因为我们知道这一个其实就表示了新的单词与单词见的那种关系, 得到一个[batch_size, num_filters, 1]的张量, 然后把第二维度去掉,再进行全连接层。具体代码如下:

class CNN(nn.Module):def __init__(self, vocab_size, embedding_size, num_filters, filter_size, out_size, dropout, pad_idx):super(CNN, self).__init__()self.embedding = nn.Embedding(vocab_size, embedding_size, padding_idx=pad_idx)self.conv = nn.Conv2d(in_channels=1, out_channels=num_filters, kernel_size=(filter_size, embedding_size))self.linear = nn.Linear(num_filters, out_size)self.dropout = nn.Dropout(dropout)def forward(self, text):text = text.permute(1, 0)     # [batch_size, seq_len]embedded = self.embedding(text)      # [batch_size, seq_len, emb_dim]embedded = embedded.unsqueeze(1)    # [batch_size, 1, seq_len, emb_dim]conved = F.relu(self.conv(embedded))   # [batch_size, num_filters, seq_len-filter_size+1]conved = conved.squeeze(3)pooled = F.max_pool1d(conved, conved.shape[2])   # 把第二个维度压扁, [batch_size, numf, 1]pooled = pooled.squeeze(2)    # [batch_size, num_filters]pooled = self.dropout(pooled)   # [batch_size, num_filters]return self.linear(pooled)

CNN网络的强大在于还可以使用多种卷积核, 进行多层卷积的操作, 这时候就可以把这些卷积层写到一个ModuleList里面去。 看下面这种方式:

class CNN_Model(nn.Module):def __init__(self, vocab_size, embedding_dim, n_filters, filter_sizes, output_dim, dropout, pad_idx):super(CNN_Model, self).__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=pad_idx)self.convs = nn.ModuleList([nn.Conv2d(in_channels=1, out_channels=n_filters, kernel_size=(fs, embedding_dim))for fs in filter_sizes])self.fc = nn.Linear(len(filter_sizes) * n_filters, output_dim)self.dropout = nn.Dropout(dropout)def forward(self, text):text = text.permute(1, 0)   # [batch_size, seq_len]embedded = self.embedding(text)  # [batch_size, seq_len, embed_dim]embedded = embedded.unsqueeze(1)   # [batch_size, 1, seq_len, embed_dim]conved = [F.relu(conv(embedded)).squeeze(3) for conv in self.convs]# conv_n: [batch_size, num_filters, seq_len-fliter[n]+1]pooled = [F.max_pool1d(conv, conv.shape[2]).squeeze(2) for conv in conved]# pooled_n: [batch_size, n_filters]cat = self.dropout(torch.cat(pooled, dim=1))  # [batch_size, n_filters*len(filter_size)]return self.fc(cat)

这时候就可以建立一个这样的模型:

INPUT_DIM = len(TEXT.vocab)
EMBEDDING_DIM = 100
N_FILTERS = 100
OUTPUT_DIM = 1
#FILTER_SIZE = 3
FILTER_SIZE = [3, 4, 5]   # 使用多层卷积, 每一层用不同的卷积核
DROPOUT = 0.5
PAD_IDX = TEXT.vocab.stoi[TEXT.pad_token]model = CNN_Model(INPUT_DIM, EMBEDDING_DIM, N_FILTERS, FILTER_SIZE, OUTPUT_DIM, DROPOUT, PAD_IDX)

训练的方式和上面一样, 这里也不再多说。 下面测试一下CNN:

model.load_state_dict(torch.load('CNN-model.pt'))
test_loss, test_acc = evaluate(model, test_iterator, criterion)
print(f'Test Loss: {test_loss:.3f} | Test Acc: {test_acc*100:.2f}%')## Test Loss: 0.333 | Test Acc: 85.68%

所以从这次的实验来看, 可以发现CNN Model的效果是最好的, 所以以后情感分类的时候, 也可以考虑一下CNN Model。

4. 小总

下面简单的总结一下这节课, 这节课其实是比较简单的, 这些课现在听起来有个感觉就是这个课基本上是纯实践, 虽然说是入门, 但不是入门那么简单, 每次看老师盲敲这些东西甚是羡慕, 但换成自己就不行了,所以这个课还是感觉最好是先跟着老师的jupyter先过一遍, 然后再听课, 这时候效率会高一些, 如果是先听课, 再敲代码的话感觉课基本上是白听, 老师上课全程会秀代码, 所以应该先亲自敲一遍, 有不懂的再通过课程查缺补漏, 后面都会采用这样的听课方式。

有点说远了, 看这节课的话主要是围绕着一个情感分类的任务进行的展开, 然后是用Pytorch实现了三个模型, WordAveraging, 双向LSTM和CNN Model, 这次重点是这三个网络的积累和学习, 另外学习到了一些习惯或者经验, 这里也稍微总结一下:

  1. 用Pytorch搭建神经网络的时候, 可以先搭一个框架, 然后从下往上进行展开, 从forward到init, 再到init的参数
  2. 神经网络写前向传播的时候, 要养成核对张量维度的习惯
  3. 神经网络训练的时候, 可以把train和evaluate写成函数的方式, 这样就有利于换了模型也不用改变训练的代码
  4. 要学会保存最好的模型, 还要学会打印一些日志信息帮助我们看看模型是不是正常工作, 这次仿佛提供了模板
  5. 这个是关于情感分类时训练模型的技巧, 就是embedding的初始化参数可以用已经训练好的词向量, 在这个基础上进行微调
  6. 情感分类或者语言模型, 有个torchtext包可以帮助我们准备数据, 数据初始化或者是构建成Iterator。

所以, 这节课的收获还是蛮大的。下两节课就是关于图片的知识了, 课程已经进行到一半了, 继续rush吧

Pytorch入门+实战系列五:Pytorch情感分类相关推荐

  1. PyTorch 入门实战(五)——2013kaggle比赛 猫狗大战的实现

    承接上一篇:PyTorch 入门实战(四)--利用Torch.nn构建卷积神经网络 PyTorch入门实战 1.博客:PyTorch 入门实战(一)--Tensor 2.博客:PyTorch 入门实战 ...

  2. Pytorch入门+实战系列七:图片风格迁移和GAN

    Pytorch官方文档:https://pytorch.org/docs/stable/torch.html? 1. 写在前面 今天开始,兼顾Pytorch学习, 如果刚刚接触深度学习并且想快速搭建神 ...

  3. PyTorch 入门实战

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_36556893/article/ ...

  4. PyTorch 入门实战(四)——利用Torch.nn构建卷积神经网络

    承接上一篇:PyTorch 入门实战(三)--Dataset和DataLoader PyTorch入门实战 1.博客:PyTorch 入门实战(一)--Tensor 2.博客:PyTorch 入门实战 ...

  5. 网易云课程:深度学习与PyTorch入门实战

    网易云课程:深度学习与PyTorch入门实战 01 深度学习初见 1.1 深度学习框架简介 1.2 pytorch功能演示 2开发环境安装 3回归问题 3.1简单的回归问题(梯度下降算法) 3.3回归 ...

  6. 视频教程-深度学习与PyTorch入门实战教程-深度学习

    深度学习与PyTorch入门实战教程 新加坡国立大学研究员 龙良曲 ¥399.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术好课免费看 APP订阅课程,领取优惠,最少立减5元 ↓ ...

  7. PyTorch 入门实战(三)——Dataset和DataLoader

    承接上一篇:PyTorch 入门实战(二)--Variable 对于Dataset,博主也有着自己的理解: 关于Pytorch中dataset的迭代问题(这就是为什么我们要使用dataloader的原 ...

  8. PyTorch 入门实战(二)——Variable

    承接上一篇:PyTorch 入门实战(一)--Tensor 如何解决"Can't call numpy() on Variable that requires grad. Use var.d ...

  9. Spark入门实战系列--8.Spark MLlib(上)--机器学习及SparkMLlib简介

    [注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 1.机器学习概念 1.1 机器学习的定义 在维基百科上对机器学习提出以下几种定义: l&qu ...

  10. Spark入门实战系列--4.Spark运行架构

    注]该系列文章以及使用到安装包/测试数据 可以在<倾情大奉送--Spark入门实战系列>获取 1. Spark运行架构 1.1 术语定义 lApplication:Spark Applic ...

最新文章

  1. 三步走——带你打造一份完美的数据科学家简历|(附件有PPT福利)
  2. TCP/IPICMP报文的分类
  3. Git 使用规范流程
  4. 读书笔记 《Perl语言入门》 Day 1
  5. python啥意思-python是什么意思
  6. php中文网企业网站,闻名 PHP企业网站系统 weenCompany v5.3.0 简体中文 UTF8
  7. redis之sorted sets类型及操作
  8. css毛玻璃效果白边_使用css模拟vista毛玻璃效果
  9. upload file to server
  10. CSS 基础入门语法
  11. html元素按压高亮效果
  12. [转载]用 FFMPEG 合并 MP4 视频
  13. 软件设计师-知识产权和标准化知识
  14. ASCII码对照表 (0-255)
  15. 重装机兵3 完美攻略修正版
  16. Linux系统编程思维导图:基础指令,常用工具,进程,基础IO,IPC,线程;思维导图因为图片过大所以放了链接,需要的可以下载
  17. 程序员如何阅读英文文档
  18. 用css hack解决IE5 IE5.5 IE6 Firefox浏览器兼容性
  19. c语言字母表输出大写字母,c语言输入一个大写字母,输出字母表中它前面的字母和后面的字母.如果...
  20. 【Traffmonetizer】利用闲置电脑/VPS/安卓手机/树莓派来挂机

热门文章

  1. EasyCamera中海康摄像头语音对讲和云台控制转发实现
  2. SQL数据库学习,常用语句查询大全
  3. JSP介绍及视频教程
  4. vscode设置eclipse快捷键
  5. MySQL官方提供的日志分析工具_MySQL 日志分析的几款工具-Fun言
  6. 人工智能在围棋程序中的应用
  7. dnf打团正在连接服务器进不去是吗鬼,DNF韩服大转移版本开启 上线送迷你女鬼剑宠物...
  8. 约瑟夫问题 c语言数组,约瑟夫问题的数组实现
  9. 桌面计算机系统乏,桌面管理软件那点事
  10. qcom usb驱动下载_艾肯Mobile Q驱动下载