赞
踩
从之前的文章中介绍过RNN
的优点是能够捕捉到序列的时序信息,这可能有利于捕获长文本的语义。但是RNN
对于文本序列后面的单词获取到的语义会更多,故RNN
是一个有偏倚的模型。而CNN
能够捕获到全局的信息,它可以很好地确定文本中带有最大池化层的识别性短语。因此,与递归或循环神经网络相比,CNN
可以更好地捕捉文本的语义。于是为了综合两者的优点,提出了TextRCNN
模型。主要用于解决文本分类问题。
首先,我们应用一个双向的循环结构(LSTM
,GRU
),与传统的基于窗口的神经网络相比,它可以大大减少噪声,从而最大程度地捕捉上下文信息。此外,该模型在学习文本表示时可以保留更大范围的词序。其次,我们使用了一个可以自动判断哪些特性在文本分类中扮演关键角色的池化层(max-pooling
),以捕获文本中的关键组件。我们的模型结合了RNN的结构和最大池化层,利用了循环神经模型和卷积神经模型的优点。此外,我们的模型显示了O(n)的时间复杂度,它与文本长度的长度是线性相关的。
如下图是作者提出的模型框架,输入是一个文本sentence
,它可以看成是由一系列单词组成的(w1
,w2
…)。输出是一个概率分布,最大的那个位置对应文章属于的类别K 。
RCNN整体的模型构建流程如下:
Bi-LSTM
获得上下文的信息,类似于语言模型。Bi-LSTM
获得的隐层输出和词向量拼接[fwOutput
, wordEmbedding
, bwOutput
]。softmax
分类。RCNN整体的运算过程为:
word-embedding
层RNN
(这里的 RNN cell
可以使用 lstm
或者 gru
或者最简单的)双向的RNN
能够更好的捕捉上下文关系tanh
或者sigmod
)得到图中所示的
y
(
2
)
y^{(2)}
y(2)softmax
分类或者fc
映射,得到图中最终结果。# coding: UTF-8 import torch import torch.nn as nn import torch.nn.functional as F class Config(object): """配置参数""" def __init__(self): self.model_name = 'TextRCNN' self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 设备 self.dropout = 1.0 # 随机失活 self.num_classes = 10 # 类别数 self.n_vocab = 10000 # 词表大小,在运行时赋值 self.num_epochs = 10 # epoch数 self.batch_size = 128 # mini-batch大小 self.pad_size = 32 # 每句话处理成的长度(短填长切) self.learning_rate = 1e-3 # 学习率 self.embed = 300 # 字向量维度, 若使用了预训练词向量,则维度统一 self.hidden_size = 256 # lstm隐藏层 self.num_layers = 1 # lstm层数 '''Recurrent Convolutional Neural Networks for Text Classification''' class Model(nn.Module): def __init__(self, config): super(Model, self).__init__() self.embedding = nn.Embedding(config.n_vocab, config.embed, padding_idx=config.n_vocab - 1) self.lstm = nn.LSTM(config.embed, config.hidden_size, config.num_layers, bidirectional=True, batch_first=True, dropout=config.dropout) self.maxpool = nn.MaxPool1d(config.pad_size) self.fc = nn.Linear(config.hidden_size * 2 + config.embed, config.num_classes) def forward(self, x): print(x) x, _ = x # torch.Size([128, 32]) embed = self.embedding(x) # [batch_size, seq_len, embeding]=[128,32,300] out, _ = self.lstm(embed) # [batch_size, seq_len, hiden_size*2]=[128,32,512] out = torch.cat((embed, out), 2) # [batch_size, seq_len, hiden_size*2]=[128,32,512+300] out = F.relu(out) # ReLU 激活函数将所有负数变换为零,而保持正数不变 [batch_size, seq_len, hiden_size*2]=[128,32,512+300] out = out.permute(0, 2, 1) # 将张量 out 的第二个和第三个维度进行交换。[128,812,32] out = self.maxpool(out).squeeze() # config.pad_size=32,则maxpool之后,维度为[128,812,1],经过压缩之后变为[128,812] out = self.fc(out) # [128,812]====>[128,10] return out config=Config() model=Model(config) print(model)
输出:
Model(
(embedding): Embedding(10000, 300, padding_idx=9999)
(lstm): LSTM(300, 256, batch_first=True, dropout=1.0, bidirectional=True)
(maxpool): MaxPool1d(kernel_size=32, stride=32, padding=0, dilation=1, ceil_mode=False)
(fc): Linear(in_features=812, out_features=10, bias=True)
)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。