記初次除錯CNN做文字向量表示
阿新 • • 發佈:2020-07-05
心得:
卷積操作在影象處理的領域應用廣泛,影象做卷積處理有一個天然的好處,即:每個畫素點的位置與相鄰位置相對固定,也就是說,除了邊緣,每一個節點都有相同數量的相鄰節點。所以卷積操作相對容易。
但是,隨著文字表示的發展,用向量來表示文字的思想應用的越來越廣泛深入。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的嵌入]...]