導讀git
最近在梳理文本分類的各個神經網絡算法,特意一個來總結下。接下來將要一個文章一個文章的講解各個算法的理論與實踐。目錄暫定爲:github
多通道卷積神經網絡(multi_channel_CNN)算法
深度卷積神經網絡(deep_CNN)網絡
基於字符的卷積神經網絡(Char_CNN)app
循環與卷積神經網絡並用網絡(LSTM_CNN)dom
樹狀循環神經網絡(Tree-LSTM)ide
Transformer(目前經常使用於NMT)函數
etc..spa
以後的之後再補充。今天咱們先講第一個,多通道卷積神經網絡。orm
先前知識補充
先說點基礎的,咱們最剛開始的分類其實就是embedding層以後直接通過線性層進行降維,將其映射到分類上,圖爲:
而後由於參數太多,計算太慢,因此產生了pooling池化層,取指定維度的一個參數表明整個維度,從而大大下降了計算量,並且效果還不錯。圖爲:
以後又有人想到沒有充分的利用到句子的上下詞語的關係,因此就講圖像算法的CNN運用到了NLP上,這個就至關於NLP裏的n-gram(unigram,bigram,trigram...)同樣,尋找相鄰詞語組合造成的特徵。圖爲:
有了上面的基礎,咱們引出multi_channel_CNN就容易多了。
multi_channel_CNN
多通道,就是CNN中的一次性卷積要處理的多少組數據。好比圖像中,若是是隻有灰度值的圖像就只有一個通道,若是是彩色圖片的話,就會RGB三個圖像(也就是三個通道)。那麼NLP中怎麼利用這個多通道特徵呢?有人就想了NLP中不就一個句子長度 * embed維度組成的一個二維輸入嗎?是這樣的,剛開始咱們用的都是單通道的。
可是有人就提出了這樣的想法:
初始化兩個不一樣的embedding,將句子用兩個embedding表示出來,這樣就能夠有兩個通道了。
時間確實是這樣的,可是咱們經常使用的是一個是隨機初始化的embedding,另外一個是使用預訓練embedding(w2v or GloVe ...)。圖爲:
實踐
這個其實和圖像是想的差很少了。(pytorch)
class Multi_Channel_CNN 初始化:
def __init__(self, opts, vocab, label_vocab):
super(Multi_Channel_CNN, self).__init__()
random.seed(opts.seed)
torch.manual_seed(opts.seed)
torch.cuda.manual_seed(opts.seed)
self.embed_dim = opts.embed_size
self.word_num = vocab.m_size
self.pre_embed_path = opts.pre_embed_path
self.string2id = vocab.string2id
self.embed_uniform_init = opts.embed_uniform_init
self.stride = opts.stride
self.kernel_size = opts.kernel_size
self.kernel_num = opts.kernel_num
self.label_num = label_vocab.m_size
self.embed_dropout = opts.embed_dropout
self.fc_dropout = opts.fc_dropout
self.embeddings = nn.Embedding(self.word_num, self.embed_dim)
self.embeddings_static = nn.Embedding(self.word_num, self.embed_dim)
if opts.pre_embed_path != '':
embedding = Embedding.load_predtrained_emb_zero(self.pre_embed_path, self.string2id)
self.embeddings_static.weight.data.copy_(embedding)
else:
nn.init.uniform_(self.embeddings_static.weight.data, -self.embed_uniform_init, self.embed_uniform_init)
nn.init.uniform_(self.embeddings.weight.data, -self.embed_uniform_init, self.embed_uniform_init)
# 2 convs
self.convs = nn.ModuleList(
[nn.Conv2d(2, self.embed_dim, (K, self.embed_dim), stride=self.stride, padding=(K // 2, 0)) for K in self.kernel_size])
in_fea = len(self.kernel_size)*self.kernel_num
self.linear1 = nn.Linear(in_fea, in_fea // 2)
self.linear2 = nn.Linear(in_fea // 2, self.label_num)
self.embed_dropout = nn.Dropout(self.embed_dropout)
self.fc_dropout = nn.Dropout(self.fc_dropout)
這個部分主要將輸入的通道數1改成2便可。
數據流通部分:
def forward(self, input):
static_embed = self.embeddings_static(input) # torch.Size([64, 39, 100])
embed = self.embeddings(input) # torch.Size([64, 39, 100])
x = torch.stack([static_embed, embed], 1) # torch.Size([64, 2, 39, 100])
out = self.embed_dropout(x)
l = []
for conv in self.convs:
l.append(F.relu(conv(out)).squeeze(3)) # torch.Size([64, 100, 39])
out = l
l = []
for i in out:
l.append(F.max_pool1d(i, kernel_size=i.size(2)).squeeze(2)) # torch.Size([64, 100])
out = torch.cat(l, 1) # torch.Size([64, 300])
out = self.fc_dropout(out)
out = self.linear1(out)
out = self.linear2(F.relu(out))
return out
這裏主要就是一個stack函數的應用,將兩個embedding放到一個新的維度裏。
數據對比
能夠明顯看出多通道優勢仍是很突出的。
github地址:
https://github.com/zenRRan/Sentiment-Analysis/blob/master/models/multi_channel_CNN.py
歡迎fork,有問題你們儘管指出!
PS:上述圖片均來自於導師張梅山,唐都鈺的《Deep Learning in Natural Language Processing》的情感分析篇。
IELTS a bit
rival n. 競爭對手
v. 與...相匹敵
roar n/v. 咆哮,吼叫
robust adj. 強勁的;富有活力的
slippery adj. 滑的;光滑的