本文共 2947 字,大约阅读时间需要 9 分钟。
应用:垃圾邮件分类、主题分类、情感分析
workflow:
class BiRNN(nn.Block): def __init__(self, vocab, embed_size, num_hiddens, num_layers, **kwargs): super(BiRNN, self).__init__(**kwargs) self.embedding = nn.Embedding(len(vocab), embed_size) self.encoder = rnn.LSTM(num_hiddens, num_layers=num_layers, bidirectional=True, input_size=embed_size) self.decoder = nn.Dense(2) def forward(self, inputs): # inputs 形状是(批量大小,词数),因为 LSTM 需要将序列作为第一维, # 所以将输入转置后再提取词特征,输出形状为(词数,批量大小,词向量长度)。 embeddings = self.embedding(inputs.T) # states 形状是(词数,批量大小,2* 隐藏单元个数)。 states = self.encoder(embeddings) # 连结初始时间步和最终时间步的隐藏状态作为全连接层输入。 # 它的形状为(批量大小,2* 隐藏单元个数)。 encoding = nd.concat(states[0], states[-1]) outputs = self.decoder(encoding) return outputs
这边的LSTM是双向的,把每个h的h_0和h_1的结果contact作为最后的h输出。初始的包括反向rnn对句子的编码信息,最终的包括正向rnn对句子的编码信息。
class TextCNN(nn.Block): def __init__(self, vocab, embed_size, kernel_sizes, num_channels, **kwargs): super(TextCNN, self).__init__(**kwargs) self.embedding = nn.Embedding(len(vocab), embed_size) # 不参与训练的嵌入层。 self.constant_embedding = nn.Embedding(len(vocab), embed_size) self.dropout = nn.Dropout(0.5) self.decoder = nn.Dense(2) # 时序最大池化层没有权重,所以可以共用一个实例。 self.pool = nn.GlobalMaxPool1D() self.convs = nn.Sequential() # 创建多个一维卷积层。 for c, k in zip(num_channels, kernel_sizes): self.convs.add(nn.Conv1D(c, k, activation='relu')) def forward(self, inputs): # 将两个嵌入层的输出,其形状是(批量大小,词数,词向量维度),在上连结。 embeddings = nd.concat( self.embedding(inputs), self.constant_embedding(inputs), dim=2) # 然后将词向量维度,这是一维卷积层的通道维,调整到第二维。 embeddings = embeddings.transpose((0, 2, 1)) # 对于第 i 个一维卷积层,在时序最大池化后会得到一个形状为(批量大小,通道大小,1) # 的矩阵。使用 flatten 函数去掉最后一个维度,然后在通道维上连结。 encoding = nd.concat(*[nd.flatten( self.pool(conv(embeddings))) for conv in self.convs], dim=1) # 作用丢弃层后使用全连接层得到输出。 outputs = self.decoder(self.dropout(encoding)) return outputs
改进点: