沈阳企业网站建设,惠州免费建站模板,苏州建站公司速找苏州聚尚网络,做暧暧网站在线看文章目录1 数据准备1.1 数据集拆分1.2 创建词库vocabulary1.3 batch数据#xff0c;创建Iterator2 Word Averaging模型3 RNN模型4 CNN三种分类方式#xff1a;Word Averaging模型、RNN、CNN。1 数据准备
第一步是准备数据。代码中用到的类库有spacy、torchtext。 torchtext中…
文章目录1 数据准备1.1 数据集拆分1.2 创建词库vocabulary1.3 batch数据创建Iterator2 Word Averaging模型3 RNN模型4 CNN三种分类方式Word Averaging模型、RNN、CNN。1 数据准备
第一步是准备数据。代码中用到的类库有spacy、torchtext。 torchtext中有data.Field用来处理每个文本字段。dataLabelFiled处理标签字段。
1.1 数据集拆分
将数据集分为训练集、验证集和测试集。了解每种数据集的数据量查看每一条数据的样子。 每一条句子是一个样本。
1.2 创建词库vocabulary
TEXT.build_vocab(train_data, max_size25000, vectorsglove.6B.100d, unk_inittorch.Tensor.normal_)
LABEL.build_vocab(train_data)设置词表大小用词向量初始化词表。
1.3 batch数据创建Iterator
训练的时候是一个batch一个batch训练的。torchtext会将短句子pad到和最长的句子长度相同。
train_iterator, valid_iterator, test_iterator data.BucketIterator.splits((train_data, valid_data, test_data), batch_sizeBATCH_SIZE,devicedevice)数据准备好了就开始用模型训练吧。
2 Word Averaging模型
我们首先介绍一个简单的Word Averaging模型。这个模型非常简单我们把每个单词都通过Embedding层投射成word embedding vector然后把一句话中的所有word vector做个平均就是整个句子的vector表示了。 接下来把这个sentence vector传入一个Linear层做分类即可。 怎么做平均呢我们使用avg_pool2d来做average pooling。我们的目标是把sentence length那个维度平均成1然后保留embedding这个维度。 avg_pool2d的kernel size是 (embedded.shape[1], 1)所以句子长度的那个维度会被压扁。
import torch.nn as nn
import torch.nn.functional as Fclass 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_idxpad_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]return self.fc(pooled)接下来就是模型训练、评价。
优化函数nn.BCEWithLogitsLoss() 优化方法Adm 评价损失函数值准确率。
3 RNN模型 我们使用最后一个hidden state hTh_ThT来表示整个句子。 然后我们把hTh_ThT通过一个线性变换f然后用来预测句子的情感。
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_idxpad_idx)self.rnn nn.LSTM(embedding_dim, hidden_dim, num_layersn_layers, bidirectionalbidirectional, dropoutdropout)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 layers#and apply dropouthidden self.dropout(torch.cat((hidden[-2,:,:], hidden[-1,:,:]), dim1)) # [batch size, hid dim * num directions]return self.fc(hidden.squeeze(0))
4 CNN
CNN可以把每个局域的特征提出来。在用于句子情感分类的时候其实是做了一个ngram的特征抽取。 首先做一个embedding得到每个词的词向量是一个k维的向量。每个词的词向量结合到一起得到一个nxk的矩阵。n是单词个数。
其次卷积层filter。现在相当于一个hgram。最后转化为h个单词。 w是hxk的。 每一个h单词的窗口都会被这个filter转化。c[c1,c2,...cn−h−1]c[c_1,c_2,...c_{n-h-1}]c[c1,c2,...cn−h−1] 上图中是一个卷积核为(3,embedding_size)的卷积。每次作用于3个单词形成3-gram结果。
一般来说会选用多个卷积核下图是作用了3个(3,embedding_size)卷积核。也可以使用不同尺寸的卷积核。
第三步做一个max-over-time pooling。C^max{c}\widehat{C}max\{c\}Cmax{c}
如果有m个filter我们会得到z[C1^,C2^,...Cm^]z[\widehat{C_1},\widehat{C_2},...\widehat{C_m}]z[C1,C2,...Cm]
第四步对z做一个线性变换得到分类。
class CNN(nn.Module):def __init__(self, vocab_size, embedding_size, output_size, pad_idx, n_filters, filter_sizes, dropout):super(CNN, self).__init__()self.embedding nn.Embedding(vocab_size, embedding_size, padding_idxpad_idx)self.convs nn.ModuleList([nn.Conv2d(in_channels1, out_channelsn_filters, kernel_size(fs, embedding_size)) for fs in filter_sizes])self.linear nn.Linear(len(filter_sizes) * n_filters, output_size)self.dropout nn.Dropout(dropout)def forward(self, text):# text : [seq_len, batch_size]text text.permute(1, 0) # [batch_size,seq_len]embed self.embedding(text) # [batch_size, seq_len, embedding_size]embed embed.unsqueeze(1) # [batch_size, 1, seq_len, embedding_size]# conved中每一个的形状是[batch_size, n_filters, seq_len-filter_sizes[i]1embedding_size-embedding_size1]# 因为kernel_size的第二个维度是embedding_sizeconved [conv(embed) for conv in self.convs]# conved中每一个的形状是[batch_size, n_filters, seq_len-filter_sizes[i]1]conved [F.relu(conv).squeeze(3) for conv in conved]# pooled中的每一个形状是[batch_size, n_filters, 1]pooled [F.max_pool1d(conv, conv.shape[2]) for conv in conved]# pooled中的每一个形状是[batch_size, n_filters]pooled [conv.squeeze(2) for conv in pooled]cat self.dropout(torch.cat(pooled, dim1)) # [batch_size, len(filter_sizes) * n_filters]return self.linear(cat) # [batch_size,output_size]N_FILTERS 100
FILTER_SIZES [3, 4, 5]
DROPOUT 0.5
cnn_model CNN(VOCAB_SIZE, EMBEDDING_SIZE, OUTPUT_SIZE, PAD_IDX, N_FILTERS, FILTER_SIZES, DROPOUT)代码中的卷积核分别为(3,embedding_size)(4,embedding_size)(5,embedding_size) 每次卷积完成之后[batch_size, n_filters, seq_len-filter_sizes[i]1embedding_size-embedding_size1]最后一个维度为1。
因为多个卷积之后的形状不一样通过max_pooling层后统一变为[batch_size, n_filters]。这样就可以将多个卷积的结果拼接在一起送入全连接层。