啸林 2020-07-04
心得:
卷积操作在图像处理的领域应用广泛,图像做卷积处理有一个天然的好处,即:每个像素点的位置与相邻位置相对固定,也就是说,除了边缘,每一个节点都有相同数量的相邻节点。所以卷积操作相对容易。
但是,随着文本表示的发展,用向量来表示文本的思想应用的越来越广泛深入。textCNN是我理解的卷积在文本表示学习的开山之作,我们知道,图像领域的卷积操作,可以通过不同的卷积核收取一副或一组图像(向量)中的多个特征,那么类比来说,文本上的卷积操作,同样也是向量的卷积操作,一样可以提取文本向量的特征。
textCNN把文本描述成:词嵌入的序列,卷积操作不再左右滑动,而是只上下滑动,每次卷积操作都涉及到了上下几行(与卷积核的尺寸有关)特征也就是单词,所以我们说卷积操作可以提取到文本的上下文信息,可以更好的表示文本信息。
操作:
torch框架作为流行的深度智能框架,配置简单,操作更加适合大众思维。因此尝试使用CNN做文本的向量表示:
(1) textCNN class
:
这个是搭建的建议CNN框架,包含基础的conv层、ReLU、MeanPooling层。代码如下
import sys sys.path.append(‘/home/student/xxx/project/Branch1/‘) # sys.path.append(‘E:/for_study/pythonMLSpace/Branch1/‘) from torch import nn as nn import torch import math class bTextCNN(nn.Module): def __init__(self, param): super(bTextCNN, self).__init__() ci = 1 # RGB的通道数 文本的话相当于灰度图只一个通道 kernel_num = param[‘kernel_num‘] # 卷积核数量,输出向量维度 kernel_size = param[‘kernel_size‘] # 卷积核尺寸 vocab_size = param[‘vocab_size‘] # 文本长度n,word-level embed_dim = param[‘embed_dim‘] # 输入词嵌入的维度 dropout = param[‘dropout‘] # dropout比率 padding = param[‘padding‘] # class_num = param[‘class_num‘] # 分类数量 self.param = param # 两层卷积 # self.conv1 = nn.Conv2d(in_channels=ci, out_channels=kernel_num, kernel_size=(kernel_size[0], embed_dim)) # self.relu1 = nn.ReLU(True) # self.avgpool1 = nn.AvgPool2d(kernel_size=16) layer1 = nn.Sequential() layer1.add_module(‘CONV1‘, nn.Conv2d(in_channels=ci, out_channels=kernel_num, kernel_size=(kernel_size[0], embed_dim), padding=padding)) layer1.add_module(‘RELU1‘, nn.ReLU(True)) layer1.add_module(‘POOL1‘, nn.AvgPool2d(kernel_size=vocab_size)) self.layer1 = layer1 layer2 = nn.Sequential() layer2.add_module(‘CONV2‘, nn.Conv2d(in_channels=ci, out_channels=kernel_num, kernel_size=(kernel_size[0], kernel_num))) layer2.add_module(‘RELU2‘, nn.ReLU(True)) layer2.add_module(‘POOL2‘, nn.AvgPool2d(kernel_size=vocab_size)) self.layer2 = layer2 dropoutlayer = nn.Sequential() dropoutlayer.add_module(‘DROPOUT‘, nn.Dropout(dropout)) self.dropoutlayer = dropoutlayer # self.fc1 = nn.Linear(len(kernel_size) * kernel_num, class_num) # 全连接层 def forward(self, x): x = x.unsqueeze(0) # 增加一个维度,使之适应CNN x = x.unsqueeze(0) # 增加一个维度,使之适应CNN # print(‘input尺寸:‘ + str(x.size())) # out = self.conv1(x) # print(‘conv后尺寸:‘ + str(out.size())) # out = self.relu1(out) # print(‘relu后尺寸:‘ + str(out.size())) # out = self.avgpool1(out) # print(‘pooling后尺寸:‘ + str(out.size())) out = self.layer1(x) # out = self.layer2(out) out = self.dropoutlayer(out) return out def init_weight(self): for m in self.modules(): if isinstance(m, nn.Conv2d): n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels m.weight.data.normal_(0, math.sqrt(2. / n)) if m.bias is not None: m.bias.data.zero_() elif isinstance(m, nn.BatchNorm2d): m.weight.data.fill_(1) m.bias.data.zero_() elif isinstance(m, nn.Linear): m.weight.data.normal_(0, 0.01) m.bias.data.zero_()
(2) CNN结构设计好之后,需要考虑卷积等的参数:param
如下:
textCNN_params = { "vocab_siz"‘: 1000, # 文本长度,word-level "embed_dim": 100, # 词向量维度 "kernel_num": 128, # 卷积核数量 "kernel_size": [3], # 卷积核尺寸 "dropout": 0.2, # dropout比例 "padding": 1 # 添加边缘 }
参数的vocab_size
其实不需要设计,但是padding
参数,如果补设为1,执行到小于卷积核尺寸的词向量序列时,会报错,报错信息如下:
RuntimeError: cuDNN error: CUDNN_STATUS_BAD_PARAM
(3) 传入的词嵌入序列:
curr_word_vec1 = torch.from_numpy(np.array(question_vec_secqence[0:textCNN_params[‘vocab_size‘]]))
curr_word_vec1
的结构是二维数组:[[w1的嵌入], [w2的嵌入], [w3的嵌入]...]