最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

pytorch?實現(xiàn)情感分類問題小結(jié)

 更新時間:2023年02月14日 08:27:33   作者:Icarus_  
本文主要介紹了pytorch?實現(xiàn)情感分類問題,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1、詞表映射

無論是深度學(xué)習(xí)還是傳統(tǒng)的統(tǒng)計機器學(xué)習(xí)方法處理自然語言,都需要先將輸入的語言符號(通常為標記Token),映射為大于等于0、小于詞表大小的整數(shù),該整數(shù)也被稱作一個標記的索引值或下標。

vocab類實現(xiàn)標記和索引之間的相互映射。

from collections import defaultdict, Counter
 
class Vocab:
    def __init__(self, tokens=None):
        self.idx_to_token = list()
        self.token_to_idx = dict()
 
        if tokens is not None:
            if "<unk>" not in tokens:
                tokens = tokens + ["<unk>"]
            for token in tokens:
                self.idx_to_token.append(token)
                self.token_to_idx[token] = len(self.idx_to_token) - 1
            self.unk = self.token_to_idx['<unk>']
 
    @classmethod
    def build(cls, text, min_freq=1, reserved_tokens=None):
        token_freqs = defaultdict(int)
        for sentence in text:
            for token in sentence:
                token_freqs[token] += 1
        uniq_tokens = ["<unk>"] + (reserved_tokens if reserved_tokens else [])
        uniq_tokens += [token for token, freq in token_freqs.items() \
                        if freq >= min_freq and token != "<unk>"]
        return cls(uniq_tokens)
 
    def __len__(self):
        #返回詞表大小,即詞表有多少個互不相同的標記
        return len(self.idx_to_token)
 
    def __getitem__(self, token):
        #查找對應(yīng)輸入標記的索引
        #不存在,返回標記<unk>的索引
        return self.token_to_idx.get(token, self.unk)
 
    def convert_tokens_to_ids(self, tokens):
        #查找一系列輸入標記對應(yīng)的索引
        return [self[token] for token in tokens]
 
    def convert_ids_to_tokens(self, indices):
        #查找一系列索引值對應(yīng)的標記
        return [self.idx_to_token[index] for index in indices]
 
 
def save_vocab(vocab, path):
    with open(path, 'w') as writer:
        writer.write("\n".join(vocab.idx_to_token))
 
 
def read_vocab(path):
    with open(path, 'r') as f:
        tokens = f.read().split('\n')
    return Vocab(tokens)
 

2、詞向量層

在使用深度學(xué)習(xí)進行自然語言處理時,將一個詞(或者標記) 轉(zhuǎn)換為一個低維、稠密、連續(xù)的詞向量(也稱 Embedding ) 是一種基本的詞表示方法,通過 torch.nn 包提供的 Embedding 層即可實現(xiàn)該功能。

創(chuàng)建 Embedding 對象,需要兩個參數(shù)

  • num_embeddings :詞表的大小
  • enbeading-dim: Embedding 向量的維度

實現(xiàn)的功能是將輸入的整數(shù)張量中每個整數(shù)(通過詞表映射功能獲得標記對應(yīng)的整數(shù))映射為相應(yīng)維度(embedding_dim)的張量。

示例

import torch
from torch import nn
#詞表大小為8,Embedding向量維度3
embedding=nn.Embedding(8,3)
#輸入形狀(2,4)的整數(shù)張量,相當(dāng)于2個長度為4的整數(shù)序列,每個整數(shù)范圍是0-7
input=torch.tensor([[0,1,2,1],[4,6,6,7]],dtype=torch.long)
#調(diào)用embedding
output=embedding(input)
print(output)
print(output.shape)

輸出

張量形狀為[2, 4, 3],即在原始輸入最后增加一個長度為3 的維

tensor([[[-0.9536,  0.3367, -1.1639],
         [-0.4816, -0.8973, -0.7700],
         [ 1.9007,  1.3130, -1.2717],
         [-0.4816, -0.8973, -0.7700]],
 
        [[ 0.5755,  0.8908, -1.0384],
         [ 0.3724,  0.1216,  2.4466],
         [ 0.3724,  0.1216,  2.4466],
         [ 1.4089,  0.2458,  0.2263]]], grad_fn=<EmbeddingBackward0>)
torch.Size([2, 4, 3])

3、融入詞向量層的多層感知器

基本的多層感知器,輸入為固定大小的實數(shù)向量。如果輸人為文本,即整數(shù)序列(假設(shè)已經(jīng)利用詞表映射工具將文本中每個標記映射為了相應(yīng)的整數(shù)),在經(jīng)過多層感知器之前,需要利用詞向量層將輸入的整數(shù)映射為向量。

但是,一個序列中通常含有多個詞向量,那么如何將它們表示為一個多層感知器的輸入向量呢?一種方法是將幾個向量拼接成一個大小為的向量,其中d表示每個詞向量的大小。這樣做的一個問題是最終的預(yù)測結(jié)果與標記在序列中的位置過于相關(guān)。例如,如果在一個序列前面增加一個標記,則序列中的每個標記位置都變了,也就是它們對應(yīng)的參數(shù)都發(fā)生了變化,那么模型預(yù)測的結(jié)果可能完全不同,這樣顯然不合理。

在自然語言處理中,可以使用詞袋(Bag-Of-Words, Bow)模型解決該問題。詞袋模型指的是在表示序列時,不考慮其中元素的順序,而是將其簡單地看成是一個集合。于是就可以采用聚合操作處理一個序列中的多個詞向量,如求平均、求和或保留最大值等。融入詞向量層以及詞袋模型的多層感知器代碼如下:

import torch
from torch import nn
from torch.nn import functional as F
 
class MLP(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_class):
        super(MLP, self).__init__()
        # 詞嵌入層
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        # 線性變換:詞嵌入層->隱含層
        self.linear1 = nn.Linear(embedding_dim, hidden_dim)
        # 使用ReLU激活函數(shù)
        self.activate = F.relu
        # 線性變換:激活層->輸出層
        self.linear2 = nn.Linear(hidden_dim, num_class)
 
    def forward(self, inputs):
        embeddings = self.embedding(inputs)
        # 將序列中多個embedding進行聚合(此處是求平均值)
        embedding = embeddings.mean(dim=1)
        hidden = self.activate(self.linear1(embedding))
        outputs = self.linear2(hidden)
        # 獲得每個序列屬于某一類別概率的對數(shù)值
        probs = F.log_softmax(outputs, dim=1)
        return probs
 
mlp = MLP(vocab_size=8, embedding_dim=3, hidden_dim=5, num_class=2)
# 輸入為兩個長度為4的整數(shù)序列
inputs = torch.tensor([[0, 1, 2, 1], [4, 6, 6, 7]], dtype=torch.long)
outputs = mlp(inputs)
print(outputs)

輸出:

結(jié)果為每個序列屬于某一類別的概率的對數(shù)

tensor([[-1.1612, -0.3756],
        [-0.8089, -0.5894]], grad_fn=<LogSoftmaxBackward0>)

在實際的自然語言處理任務(wù)中,一個批次里輸人的文本長度往往是不固定的,因此無法像上面的代碼一樣簡單地用一個張量存儲詞向量并求平均值。 PyTorch 提供了一種更靈活的解決方案,即EmnbeddingBag 層。在調(diào)用 Embedding-Bag 層時,首先需要將不定長的序列拼按起來,然后使用一個偏移向量 ( Offsets ) 記錄每個序列的起始位置。

4、數(shù)據(jù)處理

第一步是將待處理的數(shù)據(jù)從硬盤或者其他地方加載到程序中,此時讀入的是原始文本數(shù)據(jù),還需要經(jīng)過分句、標記解析等 預(yù)處理過程轉(zhuǎn)換為標記序列,然后再使用詞表映射工具將每個標記映射到相應(yīng)的索引值。在此,使用 NLTK 提供的句子傾向性分析數(shù)據(jù) (sentence_polarity) 作為示例,

import torch
from vocab import Vocab
 
def load_sentence_polarity():
    from nltk.corpus import sentence_polarity
 
    #使用全部橘子集合(已經(jīng)過標記解析)創(chuàng)建詞表
    vocab = Vocab.build(sentence_polarity.sents())
 
    #褒貶各4000句子作為訓(xùn)練數(shù)據(jù),使用創(chuàng)建的詞表將標記映射為相應(yīng)的索引
    #褒義標簽為0,貶義標簽為1
    #每個樣例是一個有索引值列表和標簽組成的元祖
    train_data = [(vocab.convert_tokens_to_ids(sentence), 0)
                  for sentence in sentence_polarity.sents(categories='pos')[:4000]] \
        + [(vocab.convert_tokens_to_ids(sentence), 1)
            for sentence in sentence_polarity.sents(categories='neg')[:4000]]
 
    #其余的作為測試數(shù)據(jù)
    test_data = [(vocab.convert_tokens_to_ids(sentence), 0)
                 for sentence in sentence_polarity.sents(categories='pos')[4000:]] \
        + [(vocab.convert_tokens_to_ids(sentence), 1)
            for sentence in sentence_polarity.sents(categories='neg')[4000:]]
 
    return train_data, test_data, vocab
 
def length_to_mask(lengths):
    max_len = torch.max(lengths)
    mask = torch.arange(max_len).expand(lengths.shape[0], max_len) < lengths.unsqueeze(1)
    return mask
 
def load_treebank():
    from nltk.corpus import treebank
    sents, postags = zip(*(zip(*sent) for sent in treebank.tagged_sents()))
 
    vocab = Vocab.build(sents, reserved_tokens=["<pad>"])
 
    tag_vocab = Vocab.build(postags)
 
    train_data = [(vocab.convert_tokens_to_ids(sentence), tag_vocab.convert_tokens_to_ids(tags)) for sentence, tags in zip(sents[:3000], postags[:3000])]
    test_data = [(vocab.convert_tokens_to_ids(sentence), tag_vocab.convert_tokens_to_ids(tags)) for sentence, tags in zip(sents[3000:], postags[3000:])]
 
    return train_data, test_data, vocab, tag_vocab
 

dataset 是 Dataset 類(在torch.utils.data 包中定義)的一個對象,用于存儲數(shù)據(jù),一般需要根據(jù)具體的數(shù)據(jù)存取需求創(chuàng)建 Dataset 類的子類。如創(chuàng)建 —個BowDataset 子類,其中 Bow 是詞袋的意思。具體代碼如下

import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.utils.data import Dataset, DataLoader
from collections import defaultdict
from vocab import Vocab
from utils import load_sentence_polarity
 
class BowDataset(Dataset):
    def __init__(self, data):
        #data為原始數(shù)據(jù)
        self.data = data
    def __len__(self):
        #數(shù)據(jù)集中樣例的數(shù)目
        return len(self.data)
    def __getitem__(self, i):
        #返回下標i的數(shù)據(jù)
        return self.data[i]
 
#用于對樣本進行整理
def collate_fn(examples):
    #從獨立樣本集合中構(gòu)建各批次的輸入輸出 
    #其中,BowDataset類定義了一個樣本的數(shù)據(jù)結(jié)構(gòu),即輸入標簽和輪出標悠的元組
    # 因此,將輸入inputs定義為一個張量的列表,其中每個張量為原始句子中標記序列 
    inputs = [torch.tensor(ex[0]) for ex in examples]
    #輸出的目標targets 為該批次中全部樣例輸出結(jié)果 (0或1) 構(gòu)成的張量
    targets = torch.tensor([ex[1] for ex in examples], dtype=torch.long)
    # 獲取一個批次中每個樣例的序列長度 
    offsets = [0] + [i.shape[0] for i in inputs]
    #根據(jù)序列的長度,轉(zhuǎn)換為每個序列起始位置的偏移量 
    offsets = torch.tensor(offsets[:-1]).cumsum(dim=0)
    #將inputs列表中的張量拼接成一個大的張量 
    inputs = torch.cat(inputs)
    return inputs, offsets, targets

5、多層感知機模型的訓(xùn)練與測試

import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.utils.data import Dataset, DataLoader
from collections import defaultdict
from vocab import Vocab
from utils import load_sentence_polarity
 
 
# tqdm是一個Python模塊,能以進度條的方式顯示迭代的進度
from tqdm.auto import tqdm
 
# 超參數(shù)設(shè)置
embedding_dim = 128
hidden_dim = 256
num_class = 2
batch_size = 32
num_epoch = 5
 
# 加載數(shù)據(jù)
train_data, test_data, vocab = load_sentence_polarity()
train_dataset = BowDataset(train_data)
test_dataset = BowDataset(test_data)
train_data_loader = DataLoader(train_dataset, batch_size=batch_size, collate_fn=collate_fn, shuffle=True)
test_data_loader = DataLoader(test_dataset, batch_size=1, collate_fn=collate_fn, shuffle=False)
 
# 加載模型
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = MLP(len(vocab), embedding_dim, hidden_dim, num_class)
model.to(device) # 將模型加載到CPU或GPU設(shè)備
 
#訓(xùn)練過程
nll_loss = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001) # 使用Adam優(yōu)化器
 
model.train()
for epoch in range(num_epoch):
    total_loss = 0
    for batch in tqdm(train_data_loader, desc=f"Training Epoch {epoch}"):
        inputs, offsets, targets = [x.to(device) for x in batch]
        log_probs = model(inputs, offsets)
        loss = nll_loss(log_probs, targets)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f"Loss: {total_loss:.2f}")
 
# 測試過程
acc = 0
for batch in tqdm(test_data_loader, desc=f"Testing"):
    inputs, offsets, targets = [x.to(device) for x in batch]
    with torch.no_grad():
        output = model(inputs, offsets)
        acc += (output.argmax(dim=1) == targets).sum().item()
 
# 輸出在測試集上的準確率
print(f"Acc: {acc / len(test_data_loader):.2f}")

訓(xùn)練結(jié)果

6、基于卷積神經(jīng)網(wǎng)絡(luò)的情感分類

第3 節(jié)的詞袋模型表示文本,只考慮了文本中詞語的信息,而忽視了詞組信息,如句子

我不喜歡這部電影

詞袋模型看到文本中有“喜歡”一詞,則很可能將其識別為褒義。而卷積神經(jīng)網(wǎng)絡(luò)可以提取詞組信息,如將卷積核的大小設(shè)置為 2,則可以提取特征“不 喜歡” 等,顯然這對于最終情感極性的判斷至關(guān)重要。卷積神經(jīng)網(wǎng)絡(luò)的大部分代碼與多層感知器的實現(xiàn)一致

其中的不同之處:

  • 模型不同,需要從 nn. Module 類派生一個 CMN 子類
  • 在調(diào)用卷積神經(jīng)網(wǎng)絡(luò)時,還需要設(shè)置兩個額外的超參數(shù),分別為filter_size =3(卷積核的大?。┖蚽um_tilter =100(卷積核的個數(shù))
  • 數(shù)據(jù)整理函數(shù)(collate_fn),pad_seguence 兩數(shù)實現(xiàn)補齊 (Padding)功能,使得一個批次中 全部宇列長度相同(同最大長度序列),不足的默認使用0補齊。

除了以上不同,其他代碼與多層感知器的實現(xiàn)幾乎一致。如要實現(xiàn)一個基于新模型的情感分類任務(wù),只需要定義一個nn.Module類的子類,并修改數(shù)據(jù)整理函數(shù)(collate_fn)即可

import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.utils.data import Dataset, DataLoader
from torch.nn.utils.rnn import pad_sequence
from collections import defaultdict
from vocab import Vocab
from utils import load_sentence_polarity
 
class CnnDataset(Dataset):
    def __init__(self, data):
        self.data = data
    def __len__(self):
        return len(self.data)
    def __getitem__(self, i):
        return self.data[i]
 
#另外,數(shù)據(jù)整理函數(shù)也需要進行一些修改。  
# pad_seguence 兩數(shù)實現(xiàn)補齊 (Padding)功能,使得一個批次中 全部序列長度相同(同最大長度序列),不足的默認使用0補齊。 
def collate_fn(examples):
    inputs = [torch.tensor(ex[0]) for ex in examples]
    targets = torch.tensor([ex[1] for ex in examples], dtype=torch.long)
    # 對batch內(nèi)的樣本進行padding,使其具有相同長度
    inputs = pad_sequence(inputs, batch_first=True)
    return inputs, targets
 
#模型不同,需要從nn.Module類派生一個 CNN 子類
class CNN(nn.Module):
    def __init__(self, vocab_size, embedding_dim, filter_size, num_filter, num_class):
        super(CNN, self).__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        #padding=1表示在卷積操作之前,將序列的前后各補充1個輸入
        self.conv1d = nn.Conv1d(embedding_dim, num_filter, filter_size, padding=1)
        self.activate = F.relu
        self.linear = nn.Linear(num_filter, num_class)
    def forward(self, inputs):
        embedding = self.embedding(inputs)
        convolution = self.activate(self.conv1d(embedding.permute(0, 2, 1)))
        pooling = F.max_pool1d(convolution, kernel_size=convolution.shape[2])
        outputs = self.linear(pooling.squeeze(dim=2))
        log_probs = F.log_softmax(outputs, dim=1)
        return log_probs
 
#tqdm是一個Pyth模塊,能以進度條的方式顯示迭代的進度
from tqdm.auto import tqdm
 
#超參數(shù)設(shè)置
embedding_dim = 128
hidden_dim = 256
num_class = 2
batch_size = 32
num_epoch = 5
#在調(diào)用卷積神經(jīng)網(wǎng)絡(luò)時,還需要設(shè)置兩個額外的超參數(shù),分別為filter_size =3(卷積核的大?。┖蚽um_tilter =100(卷積核的個數(shù))。
filter_size = 3
num_filter = 100
 
#加載數(shù)據(jù)
train_data, test_data, vocab = load_sentence_polarity()
train_dataset = CnnDataset(train_data)
test_dataset = CnnDataset(test_data)
train_data_loader = DataLoader(train_dataset, batch_size=batch_size, collate_fn=collate_fn, shuffle=True)
test_data_loader = DataLoader(test_dataset, batch_size=1, collate_fn=collate_fn, shuffle=False)
 
#加載模型
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = CNN(len(vocab), embedding_dim, filter_size, num_filter, num_class)
model.to(device) #將模型加載到CPU或GPU設(shè)備
 
#訓(xùn)練過程
nll_loss = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001) #使用Adam優(yōu)化器
 
model.train()
for epoch in range(num_epoch):
    total_loss = 0
    for batch in tqdm(train_data_loader, desc=f"Training Epoch {epoch}"):
        inputs, targets = [x.to(device) for x in batch]
        log_probs = model(inputs)
        loss = nll_loss(log_probs, targets)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f"Loss: {total_loss:.2f}")
 
#測試過程
acc = 0
for batch in tqdm(test_data_loader, desc=f"Testing"):
    inputs, targets = [x.to(device) for x in batch]
    with torch.no_grad():
        output = model(inputs)
        acc += (output.argmax(dim=1) == targets).sum().item()
 
#輸出在測試集上的準確率
print(f"Acc: {acc / len(test_data_loader):.2f}")

訓(xùn)練結(jié)果

7、基于循環(huán)神經(jīng)網(wǎng)絡(luò)的情感分類

第3 節(jié)的詞袋模型還忽路了文本中詞的順序信息,因此對于兩個句子 “張三行李四”和“李四行張三”,它們的表示是完全相同的,但顯然這并不合理。循環(huán)神經(jīng)網(wǎng)絡(luò)模型能更好地對序列數(shù)據(jù)進行表示。

以長短時記憶(LSTM) 網(wǎng)絡(luò)為例。

其中,大部分代碼與前面的實現(xiàn)一致,不同之處:

  • 需要從nn.Module派生一個LSTM子類
  • forward中使用 pack_padded_sequence將變長序列打包,功能是將之前補齊過的一個小批次序列打包成一個序列,其中每個原始序列的長度存儲在lengths中,能被self.lstm直接調(diào)用
import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.utils.data import Dataset, DataLoader
from torch.nn.utils.rnn import pad_sequence, pack_padded_sequence
from collections import defaultdict
from vocab import Vocab
from utils import load_sentence_polarity
 
#tqdm是一個Python模塊,能以進度條的方式顯式迭代的進度
from tqdm.auto import tqdm
 
class LstmDataset(Dataset):
    def __init__(self, data):
        self.data = data
    def __len__(self):
        return len(self.data)
    def __getitem__(self, i):
        return self.data[i]
 
#整理函數(shù)
def collate_fn(examples):
    #獲得每個序列的長度
    lengths = torch.tensor([len(ex[0]) for ex in examples])
    inputs = [torch.tensor(ex[0]) for ex in examples]
    targets = torch.tensor([ex[1] for ex in examples], dtype=torch.long)
    # 對batch內(nèi)的樣本進行padding,使其具有相同長度
    inputs = pad_sequence(inputs, batch_first=True)
    return inputs, lengths, targets
 
#需要從nn.Module派生一個LSTM子類
class LSTM(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_class):
        super(LSTM, self).__init__()
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        self.lstm = nn.LSTM(embedding_dim, hidden_dim, batch_first=True)
        self.output = nn.Linear(hidden_dim, num_class)
 
    def forward(self, inputs, lengths):
        embeddings = self.embeddings(inputs)
        #使用 pack_padded_sequence將變長序列打包
        x_pack = pack_padded_sequence(embeddings, lengths, batch_first=True, enforce_sorted=False)
        hidden, (hn, cn) = self.lstm(x_pack)
        outputs = self.output(hn[-1])
        log_probs = F.log_softmax(outputs, dim=-1)
        return log_probs
 
embedding_dim = 128
hidden_dim = 256
num_class = 2
batch_size = 32
num_epoch = 5
 
#加載數(shù)據(jù)
train_data, test_data, vocab = load_sentence_polarity()
train_dataset = LstmDataset(train_data)
test_dataset = LstmDataset(test_data)
train_data_loader = DataLoader(train_dataset, batch_size=batch_size, collate_fn=collate_fn, shuffle=True)
test_data_loader = DataLoader(test_dataset, batch_size=1, collate_fn=collate_fn, shuffle=False)
 
#加載模型
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = LSTM(len(vocab), embedding_dim, hidden_dim, num_class)
model.to(device) #將模型加載到GPU中(如果已經(jīng)正確安裝)
 
#訓(xùn)練過程
nll_loss = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001) #使用Adam優(yōu)化器
 
model.train()
for epoch in range(num_epoch):
    total_loss = 0
    for batch in tqdm(train_data_loader, desc=f"Training Epoch {epoch}"):
        inputs, lengths, targets = [x.to(device) for x in batch]
        log_probs = model(inputs, lengths)
        loss = nll_loss(log_probs, targets)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f"Loss: {total_loss:.2f}")
 
#測試過程
acc = 0
for batch in tqdm(test_data_loader, desc=f"Testing"):
    inputs, lengths, targets = [x.to(device) for x in batch]
    with torch.no_grad():
        output = model(inputs, lengths)
        acc += (output.argmax(dim=1) == targets).sum().item()
 
#輸出在測試集上的準確率
print(f"Acc: {acc / len(test_data_loader):.2f}")

訓(xùn)練結(jié)果

8、基于 Transformer 的情感分類

基于 Transformer 實現(xiàn)情感分類與使用 LSTM 也非常相似,主要有一處不同, 即需要定義 Transformer模型。

# Defined in Section 4.6.8
 
import math
import torch
from torch import nn, optim
from torch.nn import functional as F
from torch.utils.data import Dataset, DataLoader
from torch.nn.utils.rnn import pad_sequence, pack_padded_sequence
from collections import defaultdict
from vocab import Vocab
from utils import load_sentence_polarity, length_to_mask
 
# tqdm是一個Pyth模塊,能以進度條的方式顯式迭代的進度
from tqdm.auto import tqdm
 
class TransformerDataset(Dataset):
    def __init__(self, data):
        self.data = data
    def __len__(self):
        return len(self.data)
    def __getitem__(self, i):
        return self.data[i]
 
def collate_fn(examples):
    lengths = torch.tensor([len(ex[0]) for ex in examples])
    inputs = [torch.tensor(ex[0]) for ex in examples]
    targets = torch.tensor([ex[1] for ex in examples], dtype=torch.long)
    # 對batch內(nèi)的樣本進行padding,使其具有相同長度
    inputs = pad_sequence(inputs, batch_first=True)
    return inputs, lengths, targets
 
class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout=0.1, max_len=512):
        super(PositionalEncoding, self).__init__()
 
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0).transpose(0, 1)
        self.register_buffer('pe', pe)
 
    def forward(self, x):
        x = x + self.pe[:x.size(0), :]
        return x
 
class Transformer(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, num_class,
                 dim_feedforward=512, num_head=2, num_layers=2, dropout=0.1, max_len=128, activation: str = "relu"):
        super(Transformer, self).__init__()
        # 詞嵌入層
        self.embedding_dim = embedding_dim
        self.embeddings = nn.Embedding(vocab_size, embedding_dim)
        self.position_embedding = PositionalEncoding(embedding_dim, dropout, max_len)
        # 編碼層:使用Transformer
        encoder_layer = nn.TransformerEncoderLayer(hidden_dim, num_head, dim_feedforward, dropout, activation)
        self.transformer = nn.TransformerEncoder(encoder_layer, num_layers)
        # 輸出層
        self.output = nn.Linear(hidden_dim, num_class)
 
 
    def forward(self, inputs, lengths):
        inputs = torch.transpose(inputs, 0, 1)
        #與LSTM處理情況相同,輸入的數(shù)據(jù)的第一維是批次,需要轉(zhuǎn)換為TransformerEncoder
        #所需要的第1維是長度,第二維是批次的形狀
        hidden_states = self.embeddings(inputs)
        hidden_states = self.position_embedding(hidden_states)
        #length_to_mask作用是根據(jù)批次中每個序列的長度生成mask矩陣,以便處理長度不一致的序列,忽略掉比較短的序列的無效部分
        #src_key_padding_mask的參數(shù)正好與length_to_mask的結(jié)果相反(無自注意力的部分為true)
        attention_mask = length_to_mask(lengths.to('cpu')) == False
        #根據(jù)批次中的每個序列長度生成mask矩陣
        hidden_states = self.transformer(hidden_states, src_key_padding_mask=attention_mask.to('cuda'))
        hidden_states = hidden_states[0, :, :]
        #取第一個標記的輸出結(jié)果作為分類層的輸入
        output = self.output(hidden_states)
        log_probs = F.log_softmax(output, dim=1)
        return log_probs
 
embedding_dim = 128
hidden_dim = 128
num_class = 2
batch_size = 32
num_epoch = 5
 
# 加載數(shù)據(jù)
train_data, test_data, vocab = load_sentence_polarity()
train_dataset = TransformerDataset(train_data)
test_dataset = TransformerDataset(test_data)
train_data_loader = DataLoader(train_dataset, batch_size=batch_size, collate_fn=collate_fn, shuffle=True)
test_data_loader = DataLoader(test_dataset, batch_size=1, collate_fn=collate_fn, shuffle=False)
 
# 加載模型
device = torch.device('cuda')
model = Transformer(len(vocab), embedding_dim, hidden_dim, num_class)
model.to(device) # 將模型加載到GPU中(如果已經(jīng)正確安裝)
 
# 訓(xùn)練過程
nll_loss = nn.NLLLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001) # 使用Adam優(yōu)化器
 
model.train()
for epoch in range(num_epoch):
    total_loss = 0
    for batch in tqdm(train_data_loader, desc=f"Training Epoch {epoch}"):
        inputs, lengths, targets = [x.to(device) for x in batch]
        log_probs = model(inputs, lengths)
        loss = nll_loss(log_probs, targets)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        total_loss += loss.item()
    print(f"Loss: {total_loss:.2f}")
 
# 測試過程
acc = 0
for batch in tqdm(test_data_loader, desc=f"Testing"):
    inputs, lengths, targets = [x.to(device) for x in batch]
    with torch.no_grad():
        output = model(inputs, lengths)
        acc += (output.argmax(dim=1) == targets).sum().item()
 
# 輸出在測試集上的準確率
print(f"Acc: {acc / len(test_data_loader):.2f}")

訓(xùn)練結(jié)果

到此這篇關(guān)于pytorch 實現(xiàn)情感分類問題小結(jié)的文章就介紹到這了,更多相關(guān)pytorch 實現(xiàn)情感分類 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python實現(xiàn)爬蟲抓取與讀寫、追加到excel文件操作示例

    Python實現(xiàn)爬蟲抓取與讀寫、追加到excel文件操作示例

    這篇文章主要介紹了Python實現(xiàn)爬蟲抓取與讀寫、追加到excel文件操作,結(jié)合具體實例形式分析了Python針對糗事百科的抓取與Excel文件讀寫相關(guān)操作技巧,需要的朋友可以參考下
    2018-06-06
  • Python自定義指標聚類實例代碼

    Python自定義指標聚類實例代碼

    K-means算法是最為經(jīng)典的基于劃分的聚類方法,是十大經(jīng)典數(shù)據(jù)挖掘算法之一,下面這篇文章主要給大家介紹了關(guān)于Python自定義指標聚類的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • 一文掌握6種Python中常用數(shù)據(jù)庫操作及代碼

    一文掌握6種Python中常用數(shù)據(jù)庫操作及代碼

    在數(shù)據(jù)處理和管理領(lǐng)域,Python作為一種高效、易用的編程語言,擁有豐富的數(shù)據(jù)庫操作模塊,可以輕松實現(xiàn)對關(guān)系型數(shù)據(jù)庫的數(shù)據(jù)操作,本文將介紹六種常見的Python數(shù)據(jù)庫操作模塊,需要的可以參考下
    2023-12-12
  • 詳解Python 數(shù)據(jù)庫 (sqlite3)應(yīng)用

    詳解Python 數(shù)據(jù)庫 (sqlite3)應(yīng)用

    本篇文章主要介紹了Python標準庫14 數(shù)據(jù)庫 (sqlite3),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧。
    2016-12-12
  • Python入門教程(二十七)Python的日期

    Python入門教程(二十七)Python的日期

    Python 中的日期不是其自身的數(shù)據(jù)類型,導(dǎo)入名為 datetime 的模塊,把日期視作日期對象進行處理,有許多方法可以返回有關(guān)日期對象的信息,需要的朋友可以參考下
    2023-04-04
  • python3調(diào)用R的示例代碼

    python3調(diào)用R的示例代碼

    本篇文章主要介紹了python3調(diào)用R的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Python實現(xiàn)外星人去哪了小游戲詳細代碼

    Python實現(xiàn)外星人去哪了小游戲詳細代碼

    今天為大家?guī)硪豢钚∮螒?,名叫外星人去哪了,用Python語言實現(xiàn)完成,代碼簡潔易懂,感興趣的小伙伴快來看看吧
    2022-03-03
  • Pandas高級教程之Pandas中的GroupBy操作

    Pandas高級教程之Pandas中的GroupBy操作

    通常來說groupby操作可以分為三部分:分割數(shù)據(jù),應(yīng)用變換和和合并數(shù)據(jù),本文將會詳細講解Pandas中的groupby操作,感興趣的朋友一起看看吧
    2021-07-07
  • 實例講解python中的協(xié)程

    實例講解python中的協(xié)程

    在本篇文章里我們給大家通過實例講述一下關(guān)于python中的協(xié)程相關(guān)知識點內(nèi)容,需要的朋友們可以參考下。
    2018-10-10
  • python使用正則表達式來獲取文件名的前綴方法

    python使用正則表達式來獲取文件名的前綴方法

    今天小編就為大家分享一篇python使用正則表達式來獲取文件名的前綴方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10

最新評論

安国市| 陕西省| 磴口县| 花垣县| 鄂托克前旗| 手游| 旬邑县| 沙洋县| 乌兰浩特市| 五华县| 抚宁县| 江门市| 阳高县| 岑溪市| 江都市| 高台县| 德清县| 温宿县| 从化市| 随州市| 仪陇县| 凉山| 军事| 明星| 齐齐哈尔市| 连州市| 米林县| 临沧市| 兰州市| SHOW| 日土县| 扶沟县| 德兴市| 和田县| 岳阳县| 石台县| 维西| 澄江县| 栖霞市| 金塔县| 宁津县|