手機(jī)網(wǎng)站開(kāi)發(fā)怎么收費(fèi)品牌seo推廣咨詢
系列文章目錄
1. 文本分類與詞嵌入表示,mlp來(lái)處理分類問(wèn)題
2. RNN、LSTM、GRU三種方式處理文本分類問(wèn)題
3. 評(píng)論情緒分類
還是得開(kāi)個(gè)坑,最近搞論文,使用lstm做的ssd的cache prefetching,意味著我不能再劃水了。
文章目錄
- 系列文章目錄
- [1. 文本分類與詞嵌入表示,mlp來(lái)處理分類問(wèn)題](https://blog.csdn.net/weixin_40293999/article/details/132864421) 2. RNN、LSTM、GRU三種方式處理文本分類問(wèn)題 3. 評(píng)論情緒分類 還是得開(kāi)個(gè)坑,最近搞論文,使用lstm做的ssd的cache prefetching,意味著我不能再劃水了。
- 1. 文本數(shù)據(jù)表示法與詞嵌入
- 1.1 文本是什么,如何表示?
- 1.2 文本的詞嵌入表示處理流程
- 1.3 代碼展示分詞過(guò)程
- 1.4 詞嵌入表示
- 2.簡(jiǎn)單文本分類
1. 文本數(shù)據(jù)表示法與詞嵌入
torch 是做張量計(jì)算的框架,張量只能存儲(chǔ)數(shù)字類型的值,因此無(wú)論啥樣的文本(中文、英文)都不能直接用張量表示,這就引出了文本數(shù)據(jù)的表示問(wèn)題,如何表示文本數(shù)據(jù)?
1.1 文本是什么,如何表示?
文本是常用的序列化數(shù)據(jù)類型之一。文本數(shù)據(jù)可以看作是一
個(gè)字符序列或詞的序列。對(duì)大多數(shù)問(wèn)題,我們都將文本看作
詞序列。
深度學(xué)習(xí)序列模型(如RNN及其變體)能夠較好的對(duì)序列化
數(shù)據(jù)建模。
深度學(xué)習(xí)序列模型(如RNN及其變體)可以解決類似以下領(lǐng)
域中的問(wèn)題:自然語(yǔ)言理解、文獻(xiàn)分類、情感分類、問(wèn)答系統(tǒng)等。
深度學(xué)習(xí)模型并不能理解文本,因此需要將文本轉(zhuǎn)換為數(shù)值
的表示形式。
將文本轉(zhuǎn)換為數(shù)值表示形式的過(guò)程稱為向量化過(guò)程,可以用
不同的方式來(lái)完成,
詞嵌入是單詞的一種數(shù)值化表示方式,一般情況下會(huì)將一個(gè)單詞映射到一個(gè)高維的向量中(詞向量)
來(lái)代表這個(gè)單詞
‘機(jī)器學(xué)習(xí)’表示為 [1, 2, 3]
‘深度學(xué)習(xí)’表示為 [1, 3, 3]
‘日月光華’表示為 [9, 9, 6]
對(duì)于詞向量,我們可以使用余弦相似度在計(jì)算機(jī)中來(lái)判斷
單詞之間的距離。
詞嵌入用密集的分布式向量來(lái)表示每個(gè)單詞。詞向量表示方式依賴于單詞的使用習(xí)慣,這就使得具有相似使用方式的單詞具有相似的表示形式。
Glove算法是對(duì)word2vec方法的拓展,并且更為有效。
1.2 文本的詞嵌入表示處理流程
每個(gè)較小的文本單元稱為token,將文本分解成token的過(guò)程稱為分詞(tokenization)。在 Python中有很多強(qiáng)大的庫(kù)可以用來(lái)進(jìn)行分詞.
one-hot(獨(dú)熱)編碼和詞嵌入是將token映射到向量最流行的兩種方法。
1.3 代碼展示分詞過(guò)程
import torch
import numpy as np
import string
s = "Life is not easy for any of us.We must work,and above all we must believe in ourselves.We must believe that each one of us is able to do some thing well.And that we must work until we succeed."
string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
for c in string.punctuation:s = s.replace(c," ").lower()
去掉標(biāo)點(diǎn)符號(hào)
s
'life is not easy for any of us we must work and above all we must believe in ourselves we must believe that each one of us is able to do some thing well and that we must work until we succeed ’
s.split()
['life','is','not','easy','for','any','of','us','we','must','work','and','above','all','we','must','believe','in','ourselves','we','must','believe','that','each','one','of','us','is','able','to','do','some','thing','well','and','that','we','must','work','until','we','succeed']
分詞方式(三):n-gram
向量化:one-hot emdeding
import numpy as np
np.unique(s.split())
array([‘a(chǎn)ble’, ‘a(chǎn)bove’, ‘a(chǎn)ll’, ‘a(chǎn)nd’, ‘a(chǎn)ny’, ‘believe’, ‘do’, ‘each’,
‘easy’, ‘for’, ‘in’, ‘is’, ‘life’, ‘must’, ‘not’, ‘of’, ‘one’,
‘ourselves’, ‘some’, ‘succeed’, ‘that’, ‘thing’, ‘to’, ‘until’,
‘us’, ‘we’, ‘well’, ‘work’], dtype=‘<U9’)
vocab = dict((word,index) for index, word in enumerate(np.unique(s.split())))
vocab
建立映射關(guān)系
{‘a(chǎn)ble’: 0,
‘a(chǎn)bove’: 1,
‘a(chǎn)ll’: 2,
‘a(chǎn)nd’: 3,
‘a(chǎn)ny’: 4,
‘believe’: 5,
‘do’: 6,
‘each’: 7,
‘easy’: 8,
‘for’: 9,
‘in’: 10,
‘is’: 11,
‘life’: 12,
‘must’: 13,
‘not’: 14,
‘of’: 15,
‘one’: 16,
‘ourselves’: 17,
‘some’: 18,
‘succeed’: 19,
‘that’: 20,
‘thing’: 21,
‘to’: 22,
‘until’: 23,
‘us’: 24,
‘we’: 25,
‘well’: 26,
‘work’: 27}
這是one-hot的表示方法
for index, i in enumerate(s):b[index,i] = 1
b[0:5]
array([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],[0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.,0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
1.4 詞嵌入表示
import torch
em = torch.nn.Embedding(len(vocab), 20)
s_em = em(torch.LongTensor(s))
s_em.shape
torch.Size([42, 20])
2.簡(jiǎn)單文本分類
這里要說(shuō)明一下,torch1.8 gpu 和 torchtext 0.90 版本,這倆個(gè)要匹配,否則安裝torchtext的時(shí)候,會(huì)吧torch uninstall 再install,特別麻煩。
對(duì)應(yīng)關(guān)系 ref:https://pypi.org/project/torchtext/0.14.0/
可以看到2.0的torch還沒(méi)有對(duì)應(yīng)的torchtext
import torch
import torchtext
from torchtext import data
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
from torchtext.vocab import GloVe
from torchtext.datasets import IMDB
用的是這個(gè)數(shù)據(jù)集:
IMDB:http://ai.stanford.edu/~amaas/data/sentiment/
是影評(píng),包括三個(gè)標(biāo)簽,正向、負(fù)向和未知。
TORCHTEXT.DATASETS, 所有數(shù)據(jù)集都是子類 torch.data.Dataset, 她們繼承自torch.utils.data.Dataset,并且具有split和iters實(shí)現(xiàn)的方法
切分?jǐn)?shù)據(jù)集:
TEXT = torchtext.legacy.data.Field(lower=True, fix_length=200,batch_first=True)
LABEL = torchtext.legacy.data.Field(sequential=False)
# make splits for data
train,test = torchtext.legacy.datasets.IMDB.splits(TEXT,LABEL)
構(gòu)建詞嵌入:
最多容量10000個(gè)詞,最小的頻率是出現(xiàn)10次。
# 構(gòu)建詞表 vocab 構(gòu)建train訓(xùn)練集的 top 10000個(gè)單詞做訓(xùn)練, vectors用來(lái)提供預(yù)訓(xùn)練模型
TEXT.build_vocab(train, max_size = 10000,min_freq=10, vectors=None)
LABEL.build_vocab(train)
查看頻率
TEXT.vocab.freqs
一共10002行數(shù)據(jù),因?yàn)?是unknown, 1是padding。 超過(guò)10000的詞都標(biāo)記為unknown
train_iter, test_iter = torchtext.legacy.data.BucketIterator.splits((train,test),batch_size=16)
創(chuàng)建模型
class Net(nn.Module):def __init__(self):super().__init__()self.em = nn.Embedding(len(TEXT.vocab.stoi),100) # batch*200-->batch*200*100self.fc1 = nn.Linear(200*100,1024)self.fc2 = nn.Linear(1024,3)def forward(self,x):x = self.em(x)x = x.view(x.size(0), -1)x = self.fc1(x)x = F.relu(x)x = self.fc2(x)return x
model = Net()
model
損失函數(shù):
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr=0.001)
訓(xùn)練過(guò)程:這個(gè)代碼是固定的,和我其它的文章里面也有很多
def fit(epoch, model, trainloader, testloader):correct = 0total = 0running_loss = 0model.train()for b in trainloader:x, y = b.text, b.labelif torch.cuda.is_available():x, y = b.text.to('cuda'), b.label.to('cuda')y_pred = model(x)loss = loss_fn(y_pred, y)optimizer.zero_grad()loss.backward()optimizer.step()with torch.no_grad():y_pred = torch.argmax(y_pred, dim=1)correct += (y_pred == y).sum().item()total += y.size(0)running_loss += loss.item()
# exp_lr_scheduler.step()epoch_loss = running_loss / len(trainloader.dataset)epoch_acc = correct / totaltest_correct = 0test_total = 0test_running_loss = 0 model.eval()with torch.no_grad():for b in testloader:x, y = b.text, b.labelif torch.cuda.is_available():x, y = x.to('cuda'), y.to('cuda')y_pred = model(x)loss = loss_fn(y_pred, y)y_pred = torch.argmax(y_pred, dim=1)test_correct += (y_pred == y).sum().item()test_total += y.size(0)test_running_loss += loss.item()epoch_test_loss = test_running_loss / len(testloader.dataset)epoch_test_acc = test_correct / test_totalprint('epoch: ', epoch, 'loss: ', round(epoch_loss, 3),'accuracy:', round(epoch_acc, 3),'test_loss: ', round(epoch_test_loss, 3),'test_accuracy:', round(epoch_test_acc, 3))return epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc
訓(xùn)練:
epochs = 10
train_loss = []
train_acc = []
test_loss = []
test_acc = []for epoch in range(epochs):epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch,model,train_iter,test_iter)train_loss.append(epoch_loss)train_acc.append(epoch_acc)test_loss.append(epoch_test_loss)test_acc.append(epoch_test_acc)
結(jié)果輸出:
epoch: 0 loss: 0.046 accuracy: 0.55 test_loss: 0.041 test_accuracy: 0.618
epoch: 1 loss: 0.026 accuracy: 0.809 test_loss: 0.046 test_accuracy: 0.69
epoch: 2 loss: 0.009 accuracy: 0.945 test_loss: 0.053 test_accuracy: 0.721
epoch: 3 loss: 0.004 accuracy: 0.975 test_loss: 0.068 test_accuracy: 0.729
epoch: 4 loss: 0.002 accuracy: 0.985 test_loss: 0.115 test_accuracy: 0.708
epoch: 5 loss: 0.002 accuracy: 0.989 test_loss: 0.098 test_accuracy: 0.737
epoch: 6 loss: 0.002 accuracy: 0.991 test_loss: 0.096 test_accuracy: 0.744
epoch: 7 loss: 0.001 accuracy: 0.996 test_loss: 0.108 test_accuracy: 0.742
epoch: 8 loss: 0.001 accuracy: 0.994 test_loss: 0.12 test_accuracy: 0.744
epoch: 9 loss: 0.001 accuracy: 0.994 test_loss: 0.128 test_accuracy: 0.74