记初次调试CNN做文本向量表示

心得:
卷积操作在图像处理的领域应用广泛,图像做卷积处理有一个天然的好处,即:每个像素点的位置与相邻位置相对固定,也就是说,除了边缘,每一个节点都有相同数量的相邻节点。所以卷积操作相对容易。

但是,随着文本表示的发展,用向量来表示文本的思想应用的越来越广泛深入。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的嵌入]...]

相关推荐