0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

PyTorch文本分類任務(wù)的基本流程

jf_78858299 ? 來(lái)源:天宏NLP ? 作者: tianhongzxy ? 2023-02-22 14:23 ? 次閱讀

文本分類是NLP領(lǐng)域的較為容易的入門(mén)問(wèn)題,本文記錄文本分類任務(wù)的基本流程,大部分操作使用了torchtorchtext兩個(gè)庫(kù)。

1. 文本數(shù)據(jù)預(yù)處理

首先數(shù)據(jù)存儲(chǔ)在三個(gè)csv文件中,分別是train.csv,valid.csv,test.csv,第一列存儲(chǔ)的是文本數(shù)據(jù),例如情感分類問(wèn)題經(jīng)常是用戶的評(píng)論 review ,例如imdb或者amazon數(shù)據(jù)集。第二列是情感極性 polarity ,N分類問(wèn)題的話就有N個(gè)值,假設(shè)值的范圍是0~N-1。

下面是很常見(jiàn)的文本預(yù)處理流程,英文文本的話不需要分詞,直接按空格split就行了,這里只會(huì)主要說(shuō)說(shuō)第4點(diǎn)。

1.去除非文本部分

2.分詞

3.去除停用詞

4.對(duì)英文單詞進(jìn)行 詞干提取 (stemming)和 詞型還原 (lemmatization)

5.轉(zhuǎn)為小寫(xiě)

6.特征處理

?Bag of Words?Tf-idf?N-gram?Word2vec詞干提取和詞型還原

from nltk.stem import SnowballStemmer
stemmer = SnowballStemmer("english") # 選擇語(yǔ)言
from nltk.stem import WordNetLemmatizer 
wnl = WordNetLemmatizer()

SnowballStemmer較為激進(jìn),轉(zhuǎn)換有可能出現(xiàn)錯(cuò)誤,這里較為推薦使用WordNetLemmatizer,它一般只在非??隙ǖ那闆r下才進(jìn)行轉(zhuǎn)換,否則會(huì)返回原來(lái)的單詞。

stemmer.stem('knives')
# knive
wnl.lemmatize('knives')
# knife

因?yàn)槲覜](méi)有系統(tǒng)學(xué)習(xí)和研究過(guò)NLTK的代碼,所以就不在這里展開(kāi)說(shuō)了,有興趣的可以自己去看NLTK源代碼。

2. 使用torchtext加載文本數(shù)據(jù)

本節(jié)主要是用的模塊是torchtext里的data模塊,處理的數(shù)據(jù)同上一節(jié)所描述。

首先定義一個(gè)tokenizer用來(lái)處理文本,比如分詞,小寫(xiě)化,如果你已經(jīng)根據(jù)上一節(jié)的詞干提取和詞型還原的方法處理過(guò)文本里的每一個(gè)單詞后可以直接分詞就夠了。

tokenize = lambda x: x.split()

或者也可以更保險(xiǎn)點(diǎn),使用spacy庫(kù),不過(guò)就肯定更耗費(fèi)時(shí)間了。

import spacy


spacy_en = spacy.load('en')
def tokenizer(text):
    return [toke.text for toke in spacy_en.tokenizer(text)]

然后要定義 Field ,至于Field是啥,你可以簡(jiǎn)單地把它理解為一個(gè)能夠加載、預(yù)處理和存儲(chǔ)文本數(shù)據(jù)和標(biāo)簽的對(duì)象。我們可以用它根據(jù)訓(xùn)練數(shù)據(jù)來(lái)建立詞表,加載預(yù)訓(xùn)練的Glove詞向量等等。

def DataLoader():
    tokenize = lambda x: x.split()
        # 用戶評(píng)論,include_lengths設(shè)為T(mén)rue是為了方便之后使用torch的pack_padded_sequence
    REVIEW = data.Field(sequential=True,tokenize=tokenize, include_lengths=True)
    # 情感極性
    POLARITY = data.LabelField(sequential=False, use_vocab=False, dtype = torch.long)
        # 假如train.csv文件并不是只有兩列,比如1、3列是review和polarity,2列是我們不需要的數(shù)據(jù),
    # 那么就要添加一個(gè)全是None的元組, fields列表存儲(chǔ)的Field的順序必須和csv文件中每一列的順序?qū)?yīng),
    # 否則review可能就加載到polarity Field里去了
    fields = [('review', REVIEW), (None, None), ('polarity', POLARITY)]


    # 加載train,valid,test數(shù)據(jù)
    train_data, valid_data, test_data = data.TabularDataset.splits(
                                    path = 'amazon',
                                    train = 'train.csv',
                                                                  validation = 'valid.csv',
                                                                  test = 'test.csv',
                                    format = 'csv',
                                    fields = fields,
                                    skip_header = False # 是否跳過(guò)文件的第一行
    )
    return REVIEW, POLARITY, train_data

加載完數(shù)據(jù)可以開(kāi)始建詞表。如果本地沒(méi)有預(yù)訓(xùn)練的詞向量文件,在運(yùn)行下面的代碼時(shí)會(huì)自動(dòng)下載到當(dāng)前文件夾下的'.vector_cache'文件夾內(nèi),如果本地已經(jīng)下好了,可以用Vectors指定文件名name,路徑cache,還可以使用Glove。

from torchtext.vocab import Vectors, Glove
import torch


REVIEW, POLARITY, train_data = DataLoader()
# vectors = Vectors(name='glove.6B.300d.txt', cache='.vector_cache')
REVIEW.build_vocab(train_data, # 建詞表是用訓(xùn)練集建,不要用驗(yàn)證集和測(cè)試集
                  max_size=400000, # 單詞表容量
                  vectors='glove.6B.300d', # 還有'glove.840B.300d'已經(jīng)很多可以選
                  unk_init=torch.Tensor.normal_ # 初始化train_data中不存在預(yù)訓(xùn)練詞向量詞表中的單詞
)


# print(REVIEW.vocab.freqs.most_common(20)) 數(shù)據(jù)集里最常出現(xiàn)的20個(gè)單詞
# print(REVIEW.vocab.itos[:10])                       列表 index to word
# print(REVIEW.vocab.stoi)                               字典 word to index

接著就是把預(yù)訓(xùn)練詞向量加載到model的embedding weight里去了。

pretrained_embeddings = REVIEW.vocab.vectors
model.embedding.weight.data.copy_(pretrained_embeddings)
UNK_IDX = REVIEW.vocab.stoi[REVIEW.unk_token]
PAD_IDX = REVIEW.vocab.stoi[REVIEW.pad_token]
# 因?yàn)轭A(yù)訓(xùn)練的權(quán)重的unk和pad的詞向量不是在我們的數(shù)據(jù)集語(yǔ)料上訓(xùn)練得到的,所以最好置零
model.embedding.weight.data[UNK_IDX] = torch.zeros(EMBEDDING_DIM)
model.embedding.weight.data[PAD_IDX] = torch.zeros(EMBEDDING_DIM)

然后用torchtext的迭代器來(lái)批量加載數(shù)據(jù),torchtext.data里的BucketIterator非常好用,它可以把長(zhǎng)度相近的文本數(shù)據(jù)盡量都放到一個(gè)batch里,這樣最大程度地減少padding,數(shù)據(jù)就少了很多無(wú)意義的0,也減少了矩陣計(jì)算量,也許還能對(duì)最終準(zhǔn)確度有幫助(誤)?

sort_within_batch設(shè)為T(mén)rue的話,一個(gè)batch內(nèi)的數(shù)據(jù)就會(huì)按sort_key的排列規(guī)則降序排列,sort_key是排列的規(guī)則,這里使用的是review的長(zhǎng)度,即每條用戶評(píng)論所包含的單詞數(shù)量。

train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
                                                (train_data, valid_data, test_data),
                                                batch_size=32,
                                                sort_within_batch=True,
                                                sort_key = lambda x:len(x.review),
                                                device=torch.device('cpu'))

最后就是加載數(shù)據(jù)喂給模型了。

for batch in train_iterator:
  # 因?yàn)镽EVIEW Field的inclue_lengths為T(mén)rue,所以還會(huì)包含一個(gè)句子長(zhǎng)度的Tensor
  review, review_len = batch.review  
  # review.size = (seq_length, batch_size) , review_len.size = (batch_size, )
  polarity = batch.polarity
  # polarity.size = (batch_size, )
  predictions = model(review, review_lengths)
  loss = criterion(predictions, polarity) # criterion = nn.CrossEntropyLoss()

3. 使用pytorch寫(xiě)一個(gè)LSTM情感分類器

下面是我簡(jiǎn)略寫(xiě)的一個(gè)模型,僅供參考

import torch.nn as nn
import torch.nn.functional as F
from torch.nn.utils.rnn import pack_padded_sequence
import torch




class LSTM(nn.Module):


    def __init__(self, vocab_size, embedding_dim, hidden_dim, output_dim,
                 n_layers, bidirectional, dropout, pad_idx):
        super(LSTM, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim, padding_idx=pad_idx)
        self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=n_layers,
                            bidirectional=bidirectional, dropout=dropout)
        self.Ws = nn.Parameter(torch.Tensor(hidden_dim, output_dim))
        self.bs = nn.Parameter(torch.zeros((output_dim, )))
        nn.init.uniform_(self.Ws, -0.1, 0.1)
        nn.init.uniform_(self.bs, -0.1, 0.1)
        self.dropout = nn.Dropout(p=0.5)


    def forward(self, x, x_len):
        x = self.embedding(x)
        x = pack_padded_sequence(x, x_len)
        H, (h_n, c_n) = self.lstm(x)
        h_n = self.dropout(h_n)
        h_n = torch.squeeze(h_n)
        res = torch.matmul(h_n, self.Ws) + self.bs
        y = F.softmax(res, dim=1)
        # y.size(batch_size, output_dim)
        return y

訓(xùn)練函數(shù)

def train(model, iterator, optimizer, criterion):
    epoch_loss = 0
    num_sample = 0
    correct = 0


    model.train()
    for batch in iterator:
        optimizer.zero_grad()
        review, review_lengths = batch.review
        polarity = batch.polarity
        predictions = model(review, review_lengths)
        correct += torch.sum(torch.argmax(preds, dim=1) == polarity)
        loss = criterion(predictions, polarity)
        loss.backward()
        epoch_loss += loss.item()
        num_sample += len(batch)
        optimizer.step()


    return epoch_loss / num_sample, correct.float() / num_sample


if __name__ == '__main__':
    for epoch in range(N_EPOCHS):
    train_loss, acc = train(model, train_iter, optimizer, criterion)
    print(f'\\tTrain Loss: {train_loss:.3f} | Train Acc: {acc* 100:.2f}%')

4. 注意事項(xiàng)和遇到的一些坑

1.文本情感分類需不需要去除停用詞?

?應(yīng)該是不用的,否則acc有可能下降。

2.data.TabularDataset.splits雖然好用,但是如果你只想加載訓(xùn)練集,這時(shí)候如果直接不給validation和test參數(shù)賦值,那么其他代碼和原來(lái)一樣,比如這樣

train_data = data.TabularDataset.splits(
                                       path = '',
                                       train = 'train.csv',
                                       format = 'csv',
                                       fields = fields,
                                       skip_header = False # 是否跳過(guò)文件的第一行
   )

那么底下你一定會(huì)報(bào)錯(cuò),因?yàn)?code>data.TabularDataset.splits返回的是一個(gè)元組,也就是如果是訓(xùn)練驗(yàn)證測(cè)試三個(gè)文件都給了函數(shù),就返回(train_data, valid_data, test_data),這時(shí)候你用三個(gè)變量去接受函數(shù)返回值當(dāng)然沒(méi)問(wèn)題,元組會(huì)自動(dòng)拆包。

當(dāng)只給函數(shù)一個(gè)文件train.csv時(shí),函數(shù)返回的是(train_data)而非train_data,因此正確的寫(xiě)法應(yīng)該如下

train_data = data.TabularDataset.splits(
                                       path = '',
                                       train = 'train.csv',
                                       format = 'csv',
                                       fields = fields,
                                       skip_header = False # 是否跳過(guò)文件的第一行
   )[0] # 注意這里的切片,選擇元組的第一個(gè)也是唯一一個(gè)元素賦給train_data

3.同理data.BucketIterator.splits也有相同的問(wèn)題,它不但返回的是元組,它的參數(shù)datasets要求也是以元組形式,即(train_data, valid_data, test_data)進(jìn)行賦值,否則在下面的運(yùn)行中也會(huì)出現(xiàn)各種各樣奇怪的問(wèn)題。

如果你要生成兩個(gè)及以上的迭代器,那么沒(méi)問(wèn)題,直接照上面寫(xiě)就完事了。

如果你只要生成train_iterator,那么正確的寫(xiě)法應(yīng)該是下面這樣

train_iter = data.BucketIterator(
               train_data,
               batch_size=32,
               sort_key=lambda x:len(x.review),
               sort_within_batch=True,
               shuffle=True # 訓(xùn)練集需要shuffle,但因?yàn)轵?yàn)證測(cè)試集不需要
                                                  # 可以生成驗(yàn)證和測(cè)試集的迭代器直接用data.iterator.Iterator類就足夠了
   )

4.出現(xiàn)的問(wèn)題 x = pack_padded_sequence(x, x_len) 當(dāng)數(shù)據(jù)集有長(zhǎng)度為0的句子時(shí), 就會(huì)后面報(bào)錯(cuò)

5.當(dāng)vocab size較大而訓(xùn)練數(shù)據(jù)不多的情況下,我在實(shí)驗(yàn)時(shí)發(fā)現(xiàn)Adagrad效果比Adam好,如果數(shù)據(jù)較多,可以嘗試使用RMSProp和Adam

5. 總結(jié)

不僅僅是NLP領(lǐng)域,在各大頂會(huì)中,越來(lái)越多的學(xué)者選擇使用Pytorch而非TensorFlow,主要原因就是因?yàn)樗囊子眯?,torchtext和pytorch搭配起來(lái)是非常方便的NLP工具,可以大大縮短文本預(yù)處理,加載數(shù)據(jù)的時(shí)間。

我本人之前用過(guò)tf 1.x以及keras,最終擁抱了Pytorch,也是因?yàn)樗cNumpy極其類似的用法,更Pythonic的代碼,清晰的源碼讓我在遇到bug時(shí)能一步一步找到問(wèn)題所在,動(dòng)態(tài)圖讓人能隨時(shí)看到輸出的Tensor的全部信息,這些都是Pytorch的優(yōu)勢(shì)。

現(xiàn)在tf 2.0也在不斷改進(jìn),有人稱tf越來(lái)越像pytorch了,其實(shí)pytorch也在不斷向tf學(xué)習(xí),在工業(yè)界,tf仍然處于王者地位,不知道未來(lái)pytorch能不能在工業(yè)界也與tf平分秋色,甚至更勝一籌呢?

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)預(yù)處理

    關(guān)注

    1

    文章

    18

    瀏覽量

    2741
  • nlp
    nlp
    +關(guān)注

    關(guān)注

    1

    文章

    482

    瀏覽量

    21969
  • pytorch
    +關(guān)注

    關(guān)注

    2

    文章

    795

    瀏覽量

    13078
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    pyhanlp文本分類與情感分析

    語(yǔ)料庫(kù)本文語(yǔ)料庫(kù)特指文本分類語(yǔ)料庫(kù),對(duì)應(yīng)IDataSet接口。而文本分類語(yǔ)料庫(kù)包含兩個(gè)概念:文檔和類目。一個(gè)文檔只屬于一個(gè)類目,一個(gè)類目可能含有多個(gè)文檔。比如搜狗文本分類語(yǔ)料庫(kù)迷你版.zip,下載前
    發(fā)表于 02-20 15:37

    TensorFlow的CNN文本分類

    在TensorFlow中實(shí)現(xiàn)CNN進(jìn)行文本分類(譯)
    發(fā)表于 10-31 09:27

    NLPIR平臺(tái)在文本分類方面的技術(shù)解析

    文本分類問(wèn)題就是將一篇文檔歸入預(yù)先定義的幾個(gè)類別中的一個(gè)或幾個(gè),而文本的自動(dòng)分類則是使用計(jì)算機(jī)程序來(lái)實(shí)現(xiàn)這種文本分類,即根據(jù)事先指定的規(guī)則和示例樣本,自動(dòng)從海量文檔中識(shí)別并訓(xùn)練
    發(fā)表于 11-18 17:46

    基于文章標(biāo)題信息的漢語(yǔ)自動(dòng)文本分類

    文本分類文本挖掘的一個(gè)重要組成部分,是信息搜索領(lǐng)域的一項(xiàng)重要研究課題。該文提出一種基于文章標(biāo)題信息的漢語(yǔ)自動(dòng)文本分類方法,在HNC理論的領(lǐng)域概念框架下,通過(guò)標(biāo)題
    發(fā)表于 04-13 08:31 ?10次下載

    textCNN論文與原理——短文本分類

    前言 之前書(shū)寫(xiě)了使用pytorch進(jìn)行短文本分類,其中的數(shù)據(jù)處理方式比較簡(jiǎn)單粗暴。自然語(yǔ)言處理領(lǐng)域包含很多任務(wù),很多的數(shù)據(jù)向之前那樣處理的話未免有點(diǎn)繁瑣和耗時(shí)。在pytorch中眾所周
    的頭像 發(fā)表于 12-31 10:08 ?2464次閱讀
    textCNN論文與原理——短<b class='flag-5'>文本分類</b>

    文本分類的一個(gè)大型“真香現(xiàn)場(chǎng)”來(lái)了

    任何標(biāo)注數(shù)據(jù)啦!哇,真香! 當(dāng)前的文本分類任務(wù)需要利用眾多標(biāo)注數(shù)據(jù),標(biāo)注成本是昂貴的。而半監(jiān)督文本分類雖然減少了對(duì)標(biāo)注數(shù)據(jù)的依賴,但還是需要領(lǐng)域?qū)<沂謩?dòng)進(jìn)行標(biāo)注,特別是在類別數(shù)目很大的情況下。 試想一下,我們?nèi)祟愂侨绾螌?duì)新聞
    的頭像 發(fā)表于 02-05 11:02 ?1807次閱讀
    <b class='flag-5'>文本分類</b>的一個(gè)大型“真香現(xiàn)場(chǎng)”來(lái)了

    基于深度神經(jīng)網(wǎng)絡(luò)的文本分類分析

      隨著深度學(xué)習(xí)技術(shù)的快速發(fā)展,許多研究者嘗試?yán)蒙疃葘W(xué)習(xí)來(lái)解決文本分類問(wèn)題,特別是在卷積神經(jīng)網(wǎng)絡(luò)和循環(huán)神經(jīng)網(wǎng)絡(luò)方面,出現(xiàn)了許多新穎且有效的分類方法。對(duì)基于深度神經(jīng)網(wǎng)絡(luò)的文本分類問(wèn)題進(jìn)行分析,介紹
    發(fā)表于 03-10 16:56 ?37次下載
    基于深度神經(jīng)網(wǎng)絡(luò)的<b class='flag-5'>文本分類</b>分析

    融合文本分類和摘要的多任務(wù)學(xué)習(xí)摘要模型

    文本摘要應(yīng)包含源文本中所有重要信息,傳統(tǒng)基于編碼器-解碼器架構(gòu)的摘要模型生成的摘要準(zhǔn)確性較低。根據(jù)文本分類文本摘要的相關(guān)性,提出一種多任務(wù)
    發(fā)表于 04-27 16:18 ?11次下載
    融合<b class='flag-5'>文本分類</b>和摘要的多<b class='flag-5'>任務(wù)</b>學(xué)習(xí)摘要模型

    基于不同神經(jīng)網(wǎng)絡(luò)的文本分類方法研究對(duì)比

    海量文本分析是實(shí)現(xiàn)大數(shù)據(jù)理解和價(jià)值發(fā)現(xiàn)的重要手段,其中文本分類作為自然語(yǔ)言處理的經(jīng)典問(wèn)題受到研究者廣泛關(guān)注,而人工神經(jīng)網(wǎng)絡(luò)在文本分析方面的優(yōu)異表現(xiàn)使其成為目前的主要研究方向。在此背景下,介紹卷積
    發(fā)表于 05-13 16:34 ?48次下載

    基于雙通道詞向量的卷積膠囊網(wǎng)絡(luò)文本分類算法

    的詞向量與基于特定文本分類任務(wù)擴(kuò)展的語(yǔ)境詞向量作為神經(jīng)網(wǎng)絡(luò)的2個(gè)輸入通道,并采用具有動(dòng)態(tài)路由機(jī)制的卷積膠囊網(wǎng)絡(luò)模型進(jìn)行文本分類。在多個(gè)英文數(shù)據(jù)集上的實(shí)驗(yàn)結(jié)果表明,雙通道的詞向量訓(xùn)練方式優(yōu)于單通道策略,與LSTM、RAE、 M
    發(fā)表于 05-24 15:07 ?6次下載

    基于LSTM的表示學(xué)習(xí)-文本分類模型

    文本表示和分類是自然語(yǔ)言理解領(lǐng)域的研究熱點(diǎn)。目前已有很多文本分類方法,包括卷積網(wǎng)絡(luò)、遞歸網(wǎng)絡(luò)、自注意力機(jī)制以及它們的結(jié)合。但是,復(fù)雜的網(wǎng)絡(luò)并不能從根本上提高文本分類的性能,好的
    發(fā)表于 06-15 16:17 ?18次下載

    基于注意力機(jī)制的新聞文本分類模型

    基于注意力機(jī)制的新聞文本分類模型
    發(fā)表于 06-27 15:32 ?30次下載

    帶你從頭構(gòu)建文本分類

    文本分類是 NLP 中最常見(jiàn)的任務(wù)之一, 它可用于廣泛的應(yīng)用或者開(kāi)發(fā)成程序,例如將用戶反饋文本標(biāo)記為某種類別,或者根據(jù)客戶文本語(yǔ)言自動(dòng)歸類。另外向我們平時(shí)見(jiàn)到的郵件垃圾過(guò)濾器也是
    的頭像 發(fā)表于 03-22 10:49 ?3413次閱讀

    PyTorch教程4.3之基本分類模型

    電子發(fā)燒友網(wǎng)站提供《PyTorch教程4.3之基本分類模型.pdf》資料免費(fèi)下載
    發(fā)表于 06-05 15:43 ?0次下載
    <b class='flag-5'>PyTorch</b>教程4.3之基<b class='flag-5'>本分類</b>模型

    卷積神經(jīng)網(wǎng)絡(luò)在文本分類領(lǐng)域的應(yīng)用

    顯著成就后,也逐漸被引入到文本分類任務(wù)中。卷積神經(jīng)網(wǎng)絡(luò)通過(guò)模擬人類視覺(jué)系統(tǒng)的信息處理方式,能夠有效地提取文本中的局部特征,進(jìn)而實(shí)現(xiàn)高精度的文本分類。本文將對(duì)卷積神經(jīng)網(wǎng)絡(luò)在
    的頭像 發(fā)表于 07-01 16:25 ?484次閱讀