日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人工智能 > pytorch >内容正文

pytorch

[深度学习] 自然语言处理 --- 文本分类模型总结

發(fā)布時(shí)間:2023/12/15 pytorch 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [深度学习] 自然语言处理 --- 文本分类模型总结 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文本分類

包括基于word2vec預(yù)訓(xùn)練的文本分類,與及基于最新的預(yù)訓(xùn)練模型(ELMO,BERT等)的文本分類

  • fastText 模型
  • textCNN 模型
  • charCNN 模型
  • Bi-LSTM 模型
  • Bi-LSTM + Attention 模型
  • RCNN 模型
  • Adversarial LSTM 模型
  • Transformer 模型
  • ELMO 預(yù)訓(xùn)練模型
  • BERT 預(yù)訓(xùn)練模型
  • 一 fastText 模型

    fastText模型架構(gòu)和word2vec中的CBOW很相似, 不同之處是fastText預(yù)測(cè)標(biāo)簽而CBOW預(yù)測(cè)的是中間詞,即模型架構(gòu)類似但是模型的任務(wù)不同。

    ?

    其中x1,x2,...,xN?1,xN表示一個(gè)文本中的n-gram向量,每個(gè)特征是詞向量的平均值。這和前文中提到的cbow相似,cbow用上下文去預(yù)測(cè)中心詞,而此處用全部的n-gram去預(yù)測(cè)指定類別。

    ?

    import torch.nn as nn import torch.nn.functional as Fclass FastText(nn.Module):def __init__(self, vocab_size, embedding_dim, output_dim, pad_idx):super().__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=pad_idx)self.fc = nn.Linear(embedding_dim, output_dim)def forward(self, text):#text = [sent len, batch size]embedded = self.embedding(text)#embedded = [sent len, batch size, emb dim]embedded = embedded.permute(1, 0, 2)#embedded = [batch size, sent len, emb dim]pooled = F.avg_pool2d(embedded, (embedded.shape[1], 1)).squeeze(1) #pooled = [batch size, embedding_dim]return self.fc(pooled)

    ?

    二 TextCNN模型

    TextCNN 是利用卷積神經(jīng)網(wǎng)絡(luò)對(duì)文本進(jìn)行分類的算法,由 Yoon Kim 在 “Convolutional Neural Networks for Sentence Classification” 一文? 中提出. 是2014年的算法.

    將Text的詞向量拼接在一起,就好比一張圖,只不過(guò)這個(gè)圖只是一個(gè)channel的.這里使用的就是Conv1d.

    模型的結(jié)構(gòu)是:

  • Embedding layer
  • Convolutional layer:可以用不同尺度的filter產(chǎn)生多個(gè)feature map
  • MaxPooling Layer
  • Feedfoward layer
  • Softmax Layer
  • class CNN1d(nn.Module):def __init__(self, vocab_size, embedding_dim, n_filters, filter_sizes, output_dim, dropout, pad_idx):super().__init__()self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx = pad_idx)self.convs = nn.ModuleList([nn.Conv1d(in_channels = embedding_dim, out_channels = n_filters, kernel_size = fs)for fs in filter_sizes])self.fc = nn.Linear(len(filter_sizes) * n_filters, output_dim)self.dropout = nn.Dropout(dropout)def forward(self, text):#text = [sent len, batch size]text = text.permute(1, 0)#text = [batch size, sent len]embedded = self.embedding(text)#embedded = [batch size, sent len, emb dim]embedded = embedded.permute(0, 2, 1)#embedded = [batch size, emb dim, sent len]conved = [F.relu(conv(embedded)) for conv in self.convs]#conved_n = [batch size, n_filters, sent len - filter_sizes[n] + 1]pooled = [F.max_pool1d(conv, conv.shape[2]).squeeze(2) for conv in conved]#pooled_n = [batch size, n_filters]cat = self.dropout(torch.cat(pooled, dim = 1))#cat = [batch size, n_filters * len(filter_sizes)]return self.fc(cat)

    ?

    三 CharCNN模型

    在charCNN論文Character-level Convolutional Networks for Text Classification中提出了6層卷積層 + 3層全連接層的結(jié)構(gòu),

    在此之前很多基于深度學(xué)習(xí)的模型都是使用更高層面的單元對(duì)文本或者語(yǔ)言進(jìn)行建模,比如單詞(統(tǒng)計(jì)信息或者 n-grams、word2vec 等),短語(yǔ)(phrases),句子(sentence)層面,或者對(duì)語(yǔ)義和語(yǔ)法結(jié)構(gòu)進(jìn)行分析,但是CharCNN則提出了從字符層面進(jìn)行文本分類,提取出高層抽象概念。

    字符編碼層 為了實(shí)現(xiàn) CharCNN,首先要做的就是構(gòu)建字母表,本文中使用的字母標(biāo)如下,共有 69 個(gè)字符,對(duì)其使用 one-hot 編碼,外加一個(gè)全零向量(用于處理不在該字符表中的字符),所以共 70 個(gè),所以每個(gè)字符轉(zhuǎn)化為一個(gè) 70 維的向量。文中還提到要反向處理字符編碼,即反向讀取文本,這樣做的好處是最新讀入的字符總是在輸出開始的地方。:

    ?

    模型卷積 - 池化層 文中提出了兩種規(guī)模的神經(jīng)網(wǎng)絡(luò)–large 和 small。(kernel——size的不同)都由 6 個(gè)卷積層和 3 個(gè)全連接層共 9 層神經(jīng)網(wǎng)絡(luò)組成。這里使用的是 1-D 卷積神經(jīng)網(wǎng)絡(luò)。除此之外,在三個(gè)全連接層之間加入兩個(gè) dropout 層以實(shí)現(xiàn)模型正則化。

    import torch from torch import nn import numpy as np from utils import *class CharCNN(nn.Module):def __init__(self, config, vocab_size, embeddings):super(CharCNN, self).__init__()self.config = configembed_size = vocab_size# Embedding Layerself.embeddings = nn.Embedding(vocab_size, embed_size)self.embeddings.weight = nn.Parameter(embeddings, requires_grad=False)# This stackoverflow thread explains how conv1d works# https://stackoverflow.com/questions/46503816/keras-conv1d-layer-parameters-filters-and-kernel-size/46504997conv1 = nn.Sequential(nn.Conv1d(in_channels=embed_size, out_channels=self.config.num_channels, kernel_size=7),nn.ReLU(),nn.MaxPool1d(kernel_size=3)) # (batch_size, num_channels, (seq_len-6)/3)conv2 = nn.Sequential(nn.Conv1d(in_channels=self.config.num_channels, out_channels=self.config.num_channels, kernel_size=7),nn.ReLU(),nn.MaxPool1d(kernel_size=3)) # (batch_size, num_channels, (seq_len-6-18)/(3*3))conv3 = nn.Sequential(nn.Conv1d(in_channels=self.config.num_channels, out_channels=self.config.num_channels, kernel_size=3),nn.ReLU()) # (batch_size, num_channels, (seq_len-6-18-18)/(3*3))conv4 = nn.Sequential(nn.Conv1d(in_channels=self.config.num_channels, out_channels=self.config.num_channels, kernel_size=3),nn.ReLU()) # (batch_size, num_channels, (seq_len-6-18-18-18)/(3*3))conv5 = nn.Sequential(nn.Conv1d(in_channels=self.config.num_channels, out_channels=self.config.num_channels, kernel_size=3),nn.ReLU()) # (batch_size, num_channels, (seq_len-6-18-18-18-18)/(3*3))conv6 = nn.Sequential(nn.Conv1d(in_channels=self.config.num_channels, out_channels=self.config.num_channels, kernel_size=3),nn.ReLU(),nn.MaxPool1d(kernel_size=3)) # (batch_size, num_channels, (seq_len-6-18-18-18-18-18)/(3*3*3))# Length of output after conv6 conv_output_size = self.config.num_channels * ((self.config.seq_len - 96) // 27)linear1 = nn.Sequential(nn.Linear(conv_output_size, self.config.linear_size),nn.ReLU(),nn.Dropout(self.config.dropout_keep))linear2 = nn.Sequential(nn.Linear(self.config.linear_size, self.config.linear_size),nn.ReLU(),nn.Dropout(self.config.dropout_keep))linear3 = nn.Sequential(nn.Linear(self.config.linear_size, self.config.output_size),nn.Softmax())self.convolutional_layers = nn.Sequential(conv1,conv2,conv3,conv4,conv5,conv6)self.linear_layers = nn.Sequential(linear1, linear2, linear3)def forward(self, x):embedded_sent = self.embeddings(x).permute(1,2,0) # shape=(batch_size,embed_size,seq_len)conv_out = self.convolutional_layers(embedded_sent)conv_out = conv_out.view(conv_out.shape[0], -1)linear_output = self.linear_layers(conv_out)return linear_output

    ?

    四 Bi-LSTM模型

    Bi-LSTM即雙向LSTM,較單向的LSTM,Bi-LSTM能更好地捕獲句子中上下文的信息。



    雙向循環(huán)神經(jīng)網(wǎng)絡(luò)(BRNN)的基本思想是提出每一個(gè)訓(xùn)練序列向前和向后分別是兩個(gè)循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN),而且這兩個(gè)都連接著一個(gè)輸出層。這個(gè)結(jié)構(gòu)提供給輸出層輸入序列中每一個(gè)點(diǎn)的完整的過(guò)去和未來(lái)的上下文信息。下圖展示的是一個(gè)沿著時(shí)間展開的雙向循環(huán)神經(jīng)網(wǎng)絡(luò)。六個(gè)獨(dú)特的權(quán)值在每一個(gè)時(shí)步被重復(fù)的利用,六個(gè)權(quán)值分別對(duì)應(yīng):輸入到向前和向后隱含層(w1, w3),隱含層到隱含層自己(w2, w5),向前和向后隱含層到輸出層(w4, w6)。值得注意的是:向前和向后隱含層之間沒(méi)有信息流,這保證了展開圖是非循環(huán)的。

    import torch from torch import nn import numpy as np from utils import *class TextRNN(nn.Module):def __init__(self, config, vocab_size, word_embeddings):super(TextRNN, self).__init__()self.config = config# Embedding Layerself.embeddings = nn.Embedding(vocab_size, self.config.embed_size)self.embeddings.weight = nn.Parameter(word_embeddings, requires_grad=False)self.lstm = nn.LSTM(input_size = self.config.embed_size,hidden_size = self.config.hidden_size,num_layers = self.config.hidden_layers,dropout = self.config.dropout_keep,bidirectional = self.config.bidirectional)self.dropout = nn.Dropout(self.config.dropout_keep)# Fully-Connected Layerself.fc = nn.Linear(self.config.hidden_size * self.config.hidden_layers * (1+self.config.bidirectional),self.config.output_size)# Softmax non-linearityself.softmax = nn.Softmax()def forward(self, x):# x.shape = (max_sen_len, batch_size)embedded_sent = self.embeddings(x)# embedded_sent.shape = (max_sen_len=20, batch_size=64,embed_size=300)lstm_out, (h_n,c_n) = self.lstm(embedded_sent)final_feature_map = self.dropout(h_n) # shape=(num_layers * num_directions, 64, hidden_size)# Convert input to (64, hidden_size * hidden_layers * num_directions) for linear layerfinal_feature_map = torch.cat([final_feature_map[i,:,:] for i in range(final_feature_map.shape[0])], dim=1)final_out = self.fc(final_feature_map)return self.softmax(final_out)

    ?

    五 Bi-LSTM+Attention 模型

    Bi-LSTM + Attention模型來(lái)源于論文Attention-Based Bidirectional Long Short-Term Memory Networks for Relation Classification。關(guān)于Attention的介紹見(jiàn)這篇。

      Bi-LSTM + Attention 就是在Bi-LSTM的模型上加入Attention層,在Bi-LSTM中我們會(huì)用最后一個(gè)時(shí)序的輸出向量 作為特征向量,然后進(jìn)行softmax分類。Attention是先計(jì)算每個(gè)時(shí)序的權(quán)重,然后將所有時(shí)序 的向量進(jìn)行加權(quán)和作為特征向量,然后進(jìn)行softmax分類。在實(shí)驗(yàn)中,加上Attention確實(shí)對(duì)結(jié)果有所提升。其模型結(jié)構(gòu)如下圖:

    ?

    六 RCNN模型

    Here, we have implemented Recurrent Convolutional Neural Network model for text classification, as proposed in the paper Recurrent Convolutional Neural Networks for Text Classification.

    在文本表示方面,會(huì)有超過(guò)filter_size的上下文的語(yǔ)義缺失,因此本篇文章利用RNN來(lái)進(jìn)行文本表示,中心詞左側(cè)和右側(cè)的詞設(shè)為trainable,然后將中心詞左側(cè)和右側(cè)的詞concat作為中心詞的表示。 當(dāng)前step的中心詞不輸入lstm,僅僅與左側(cè)詞和右側(cè)詞在lstm的輸出concat。

    先經(jīng)過(guò)1層雙向LSTM,該詞的左側(cè)的詞正向輸入進(jìn)去得到一個(gè)hidden state(從上往下),該詞的右側(cè)反向輸入進(jìn)去得到一個(gè)hidden state(從下往上)。再結(jié)合該詞的詞向量,生成一個(gè) 1 * 3k 的向量。

    再經(jīng)過(guò)全連接層,tanh為非線性函數(shù),得到y(tǒng)2。
    再經(jīng)過(guò)最大池化層,得出最大化向量y3.
    再經(jīng)過(guò)全連接層,sigmod為非線性函數(shù),得到最終的多分類。

    1、結(jié)合了中心詞窗口的輸入,其輸出的representation能很好的保留上下文語(yǔ)義信息
    2、全連接層+pooling進(jìn)行特征選擇,獲取全局最重要的特征


    RCNN 整體的模型構(gòu)建流程如下:
    1)利用Bi-LSTM獲得上下文的信息,類似于語(yǔ)言模型。
    2)將Bi-LSTM獲得的隱層輸出和詞向量拼接[fwOutput,wordEmbedding, bwOutput]。
    3)將拼接后的向量非線性映射到低維。
    4)向量中的每一個(gè)位置的值都取所有時(shí)序上的最大值,得到最終的特征向量,該過(guò)程類似于max-pool。
    5)softmax分類。

    import torch from torch import nn import numpy as np from torch.nn import functional as F from utils import *class RCNN(nn.Module):def __init__(self, config, vocab_size, word_embeddings):super(RCNN, self).__init__()self.config = config# Embedding Layerself.embeddings = nn.Embedding(vocab_size, self.config.embed_size)self.embeddings.weight = nn.Parameter(word_embeddings, requires_grad=False)# Bi-directional LSTM for RCNNself.lstm = nn.LSTM(input_size = self.config.embed_size,hidden_size = self.config.hidden_size,num_layers = self.config.hidden_layers,dropout = self.config.dropout_keep,bidirectional = True)self.dropout = nn.Dropout(self.config.dropout_keep)# Linear layer to get "convolution output" to be passed to Pooling Layerself.W = nn.Linear(self.config.embed_size + 2*self.config.hidden_size,self.config.hidden_size_linear)# Tanh non-linearityself.tanh = nn.Tanh()# Fully-Connected Layerself.fc = nn.Linear(self.config.hidden_size_linear,self.config.output_size)# Softmax non-linearityself.softmax = nn.Softmax()def forward(self, x):# x.shape = (seq_len, batch_size)embedded_sent = self.embeddings(x)# embedded_sent.shape = (seq_len, batch_size, embed_size)lstm_out, (h_n,c_n) = self.lstm(embedded_sent)# lstm_out.shape = (seq_len, batch_size, 2 * hidden_size)input_features = torch.cat([lstm_out,embedded_sent], 2).permute(1,0,2)# final_features.shape = (batch_size, seq_len, embed_size + 2*hidden_size)linear_output = self.tanh(self.W(input_features))# linear_output.shape = (batch_size, seq_len, hidden_size_linear)linear_output = linear_output.permute(0,2,1) # Reshaping fot max_poolmax_out_features = F.max_pool1d(linear_output, linear_output.shape[2]).squeeze(2)# max_out_features.shape = (batch_size, hidden_size_linear)max_out_features = self.dropout(max_out_features)final_out = self.fc(max_out_features)return self.softmax(final_out)

    Adversarial LSTM模型

    模型來(lái)源于論文Adversarial Training Methods For Semi-Supervised Text Classification

    ??????? 上圖中左邊為正常的LSTM結(jié)構(gòu),右圖為Adversarial LSTM結(jié)構(gòu),可以看出在輸出時(shí)加上了噪聲。

      Adversarial LSTM的核心思想是通過(guò)對(duì)word Embedding上添加噪音生成對(duì)抗樣本,將對(duì)抗樣本以和原始樣本 同樣的形式喂給模型,得到一個(gè)Adversarial Loss,通過(guò)和原始樣本的loss相加得到新的損失,通過(guò)優(yōu)化該新 的損失來(lái)訓(xùn)練模型,作者認(rèn)為這種方法能對(duì)word embedding加上正則化,避免過(guò)擬合。

    八 Transformer模型

    創(chuàng)新之處在于使用了scaled Dot-Product Attention和Multi-Head Attention

    Encoder部分


    上面的Q,K和V,被作為一種抽象的向量,主要目的是用來(lái)做計(jì)算和輔助attention。根據(jù)文章我們知道Attention的計(jì)算公式如下:

    接著是Multi-head Attention:

    ?



    這里的positional encoding需要說(shuō)明一下:


    公式中pos就代表了位置index,然后i就是index所對(duì)應(yīng)的向量值,是一個(gè)標(biāo)量,然后dmodel就是512了。之所以選擇這個(gè)函數(shù)是因?yàn)樽髡呒僭O(shè)它能夠讓模型通過(guò)相關(guān)的位置學(xué)習(xí)Attend。
    (引入這個(gè)的原因就是因?yàn)槟P屠餂](méi)有用到RNN和CNN,不能編碼序列順序,因此需要顯示的輸入位置信息.之前用到的由position embedding,作者發(fā)現(xiàn)上述方法與這個(gè)方法差不多.位置特征在這里是一種重要特征。)

    Decoder部分

    對(duì)比單個(gè)encoder和decoder,可以看出,decoder多出了一個(gè)encoder-decoder Attention layer,接收encoder部分輸出的向量和decoder自身的self attention出來(lái)的向量,然后再進(jìn)入到全連接的前饋網(wǎng)絡(luò)中去,最后向量輸出到下一個(gè)的decoder



    最后一個(gè)decoder輸出的向量會(huì)經(jīng)過(guò)Linear層和softmax層。Linear層的作用就是對(duì)decoder部分出來(lái)的向量做映射成一個(gè)logits向量,然后softmax層根據(jù)這個(gè)logits向量,將其轉(zhuǎn)換為了概率值,最后找到概率最大值的位置。這樣就完成了解碼的輸出了。

    ?

    ?

    九? ELMO 預(yù)訓(xùn)練模型

    ELMo模型是利用BiLM(雙向語(yǔ)言模型)來(lái)預(yù)訓(xùn)練詞的向量表示,可以根據(jù)我們的訓(xùn)練集動(dòng)態(tài)的生成詞的向量表示。ELMo預(yù)訓(xùn)練模型來(lái)源于論文:Deep contextualized word representations。具體的ELMo模型的詳細(xì)介紹見(jiàn)ELMO模型(Deep contextualized word representation)。

      ELMo的模型代碼發(fā)布在github上,我們?cè)谡{(diào)用ELMo預(yù)訓(xùn)練模型時(shí)主要使用到bilm中的代碼,因此可以將bilm這個(gè)文件夾拷貝到自己的項(xiàng)目路徑下,之后需要導(dǎo)入這個(gè)文件夾中的類和函數(shù)。此外,usage_cached.py,usage_character.py,usage_token.py這三個(gè)文件中的代碼是告訴你該怎么去調(diào)用ELMo模型動(dòng)態(tài)的生成詞向量。在這里我們使用usage_token.py中的方法,這個(gè)計(jì)算量相對(duì)要小一些。

      在使用之前我們還需要去下載已經(jīng)預(yù)訓(xùn)練好的模型參數(shù)權(quán)重,打開https://allennlp.org/elmo鏈接,在Pre-trained ELMo Models 這個(gè)版塊下總共有四個(gè)不同版本的模型,可以自己選擇,我們?cè)谶@里選擇Small這個(gè)規(guī)格的模型,總共有兩個(gè)文件需要下載,一個(gè)"options"的json文件,保存了模型的配置參數(shù),另一個(gè)是"weights"的hdf5文件,保存了模型的結(jié)構(gòu)和權(quán)重值(可以用h5py讀取看看)。

    ?

    十 BERT 預(yù)訓(xùn)練模型

     ?? BERT 模型來(lái)源于論文BERT: Pre-training of Deep Bidirectional Transformers for?Language Understanding。BERT模型是谷歌提出的基于雙向Transformer構(gòu)建的語(yǔ)言模型。BERT模型和ELMo有大不同,在之前的預(yù)訓(xùn)練模型(包括word2vec,ELMo等)都會(huì)生成詞向量,這種類別的預(yù)訓(xùn)練模型屬于domain transfer。而近一兩年提出的ULMFiT,GPT,BERT等都屬于模型遷移。

      BERT 模型是將預(yù)訓(xùn)練模型和下游任務(wù)模型結(jié)合在一起的,也就是說(shuō)在做下游任務(wù)時(shí)仍然是用BERT模型,而且天然支持文本分類任務(wù),在做文本分類任務(wù)時(shí)不需要對(duì)模型做修改。谷歌提供了下面七種預(yù)訓(xùn)練好的模型文件。

      

      BERT模型在英文數(shù)據(jù)集上提供了兩種大小的模型,Base和Large。Uncased是意味著輸入的詞都會(huì)轉(zhuǎn)變成小寫,cased是意味著輸入的詞會(huì)保存其大寫(在命名實(shí)體識(shí)別等項(xiàng)目上需要)。Multilingual是支持多語(yǔ)言的,最后一個(gè)是中文預(yù)訓(xùn)練模型。

    ?

    總結(jié)

    以上是生活随笔為你收集整理的[深度学习] 自然语言处理 --- 文本分类模型总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。