蘭州做網(wǎng)站哪家專業(yè)株洲專業(yè)seo優(yōu)化
文章目錄
- torchtext 庫(kù)是干什么用的 ?
- TranslationDataset 類
- 定義 Seq2Seq模型
- Encoder
- Decoder
- Seq2Seq 類
- load_terminology_dictionary 函數(shù)
- 示例用法
- train 函數(shù)
- 主程序代碼
- 模型評(píng)價(jià)
- load_sentences 函數(shù)
- translate_sentence 函數(shù)
- evaluate_bleu 函數(shù)
- 主程序
- 測(cè)試集上進(jìn)行推理
- inference 函數(shù)
- 主程序
torchtext 庫(kù)是干什么用的 ?
torchtext
是一個(gè)用于處理文本數(shù)據(jù)的庫(kù),它是 PyTorch 生態(tài)系統(tǒng)的一部分。這個(gè)庫(kù)主要用于簡(jiǎn)化文本數(shù)據(jù)的預(yù)處理和加載過(guò)程,使得在深度學(xué)習(xí)模型中使用文本數(shù)據(jù)變得更加容易。以下是 torchtext
庫(kù)的一些主要功能:
-
數(shù)據(jù)加載:
torchtext
提供了方便的 API 來(lái)加載和處理各種文本數(shù)據(jù)集,包括常見(jiàn)的數(shù)據(jù)集格式如 CSV、TSV 等。 -
文本預(yù)處理:它包含了一系列的文本預(yù)處理工具,如分詞、詞干提取、詞性標(biāo)注等,這些工具可以幫助你將原始文本轉(zhuǎn)換為模型可以理解的格式。
-
詞匯表管理:
torchtext
可以自動(dòng)構(gòu)建詞匯表,并將文本轉(zhuǎn)換為數(shù)值表示(如詞嵌入),這對(duì)于深度學(xué)習(xí)模型來(lái)說(shuō)是必不可少的。 -
數(shù)據(jù)迭代器:它提供了數(shù)據(jù)迭代器,可以方便地將數(shù)據(jù)分批加載到模型中進(jìn)行訓(xùn)練,支持多線程和多進(jìn)程加載,提高了數(shù)據(jù)加載的效率。
-
與 PyTorch 集成:
torchtext
與 PyTorch 深度集成,可以直接將處理好的數(shù)據(jù)輸入到 PyTorch 模型中,簡(jiǎn)化了整個(gè)深度學(xué)習(xí)流程。
TranslationDataset 類
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from torchtext.data.utils import get_tokenizer
from collections import Counter
import random
from torch.utils.data import Subset, DataLoader
import time# 定義數(shù)據(jù)集類
# 修改TranslationDataset類以處理術(shù)語(yǔ)
class TranslationDataset(Dataset):def __init__(self, filename, terminology):self.data = []with open(filename, 'r', encoding='utf-8') as f:for line in f:en, zh = line.strip().split('\t')self.data.append((en, zh))
class TranslationDataset(Dataset):
:定義一個(gè)繼承自Dataset
類的子類TranslationDataset
。def __init__(self, filename, terminology):
:初始化方法,接受兩個(gè)參數(shù):filename
(數(shù)據(jù)文件名)和terminology
(術(shù)語(yǔ)詞典)。self.data = []
:初始化一個(gè)空列表self.data
,用于存儲(chǔ)數(shù)據(jù)。with open(filename, 'r', encoding='utf-8') as f:
:打開(kāi)文件,使用UTF-8編碼讀取。for line in f:
:逐行讀取文件內(nèi)容。en, zh = line.strip().split('\t')
:去掉行末的換行符,并按制表符分割成英文和中文。self.data.append((en, zh))
:將英文和中文對(duì)添加到self.data
列表中。
self.terminology = terminology# 創(chuàng)建詞匯表,注意這里需要確保術(shù)語(yǔ)詞典中的詞也被包含在詞匯表中self.en_tokenizer = get_tokenizer('basic_english')self.zh_tokenizer = list # 使用字符級(jí)分詞
self.terminology = terminology
:將傳入的術(shù)語(yǔ)詞典賦值給self.terminology
。self.en_tokenizer = get_tokenizer('basic_english')
:使用basic_english
分詞器對(duì)英文進(jìn)行分詞。self.zh_tokenizer = list
:使用字符級(jí)分詞,即將中文句子拆分成單個(gè)字符。
en_vocab = Counter(self.terminology.keys()) # 確保術(shù)語(yǔ)在詞匯表中zh_vocab = Counter()print("en_vocab的值為:", en_vocab)print("zn_vocab的值為:", zn_vocab)
en_vocab = Counter(self.terminology.keys())
:初始化英文詞匯表,確保術(shù)語(yǔ)詞典中的詞在詞匯表中。zh_vocab = Counter()
:初始化中文詞匯表。print("en_vocab的值為:", en_vocab)
:打印英文詞匯表的值。print("zn_vocab的值為:", zn_vocab)
:打印中文詞匯表的值。
for en, zh in self.data:en_vocab.update(self.en_tokenizer(en))zh_vocab.update(self.zh_tokenizer(zh))
for en, zh in self.data:
:遍歷數(shù)據(jù)集中的每一對(duì)英文和中文。en_vocab.update(self.en_tokenizer(en))
:更新英文詞匯表,統(tǒng)計(jì)每個(gè)詞的出現(xiàn)頻率。zh_vocab.update(self.zh_tokenizer(zh))
:更新中文詞匯表,統(tǒng)計(jì)每個(gè)字符的出現(xiàn)頻率。
# 添加術(shù)語(yǔ)到詞匯表self.en_vocab = ['<pad>', '<sos>', '<eos>'] + list(self.terminology.keys()) + [word for word, _ in en_vocab.most_common(10000)]self.zh_vocab = ['<pad>', '<sos>', '<eos>'] + [word for word, _ in zh_vocab.most_common(10000)]
self.en_vocab = ['<pad>', '<sos>', '<eos>'] + list(self.terminology.keys()) + [word for word, _ in en_vocab.most_common(10000)]
:構(gòu)建英文詞匯表,包含特殊標(biāo)記(<pad>
,<sos>
,<eos>
)、術(shù)語(yǔ)詞典中的詞以及出現(xiàn)頻率最高的10000個(gè)詞。self.zh_vocab = ['<pad>', '<sos>', '<eos>'] + [word for word, _ in zh_vocab.most_common(10000)]
:構(gòu)建中文詞匯表,包含特殊標(biāo)記(<pad>
,<sos>
,<eos>
)以及出現(xiàn)頻率最高的10000個(gè)字符。
self.en_word2idx = {word: idx for idx, word in enumerate(self.en_vocab)}self.zh_word2idx = {word: idx for idx, word in enumerate(self.zh_vocab)}
self.en_word2idx = {word: idx for idx, word in enumerate(self.en_vocab)}
:構(gòu)建英文詞到索引的映射字典。self.zh_word2idx = {word: idx for idx, word in enumerate(self.zh_vocab)}
:構(gòu)建中文詞到索引的映射字典。
def __len__(self):return len(self.data)
def __len__(self):
:定義數(shù)據(jù)集的長(zhǎng)度方法。return len(self.data)
:返回?cái)?shù)據(jù)集的長(zhǎng)度。
def __getitem__(self, idx):en, zh = self.data[idx]en_tensor = torch.tensor([self.en_word2idx.get(word, self.en_word2idx['<sos>']) for word in self.en_tokenizer(en)] + [self.en_word2idx['<eos>']])zh_tensor = torch.tensor([self.zh_word2idx.get(word, self.zh_word2idx['<sos>']) for word in self.zh_tokenizer(zh)] + [self.zh_word2idx['<eos>']])return en_tensor, zh_tensor
def __getitem__(self, idx):
:定義獲取數(shù)據(jù)項(xiàng)的方法。en, zh = self.data[idx]
:獲取指定索引的數(shù)據(jù)項(xiàng)。en_tensor = torch.tensor([self.en_word2idx.get(word, self.en_word2idx['<sos>']) for word in self.en_tokenizer(en)] + [self.en_word2idx['<eos>']])
:將英文句子轉(zhuǎn)換為索引張量,并在末尾添加<eos>
標(biāo)記。zh_tensor = torch.tensor([self.zh_word2idx.get(word, self.zh_word2idx['<sos>']) for word in self.zh_tokenizer(zh)] + [self.zh_word2idx['<eos>']])
:將中文句子轉(zhuǎn)換為索引張量,并在末尾添加<eos>
標(biāo)記。return en_tensor, zh_tensor
:返回轉(zhuǎn)換后的英文和中文張量。
def collate_fn(batch):en_batch, zh_batch = [], []for en_item, zh_item in batch:en_batch.append(en_item)zh_batch.append(zh_item)# 對(duì)英文和中文序列分別進(jìn)行填充en_batch = nn.utils.rnn.pad_sequence(en_batch, padding_value=0, batch_first=True)zh_batch = nn.utils.rnn.pad_sequence(zh_batch, padding_value=0, batch_first=True)return en_batch, zh_batch
def collate_fn(batch):
:定義一個(gè)用于處理批量數(shù)據(jù)的函數(shù)。en_batch, zh_batch = [], []
:初始化兩個(gè)空列表,用于存儲(chǔ)批量數(shù)據(jù)。for en_item, zh_item in batch:
:遍歷批量數(shù)據(jù)中的每一對(duì)英文和中文張量。en_batch.append(en_item)
:將英文張量添加到en_batch
列表中。zh_batch.append(zh_item)
:將中文張量添加到zh_batch
列表中。en_batch = nn.utils.rnn.pad_sequence(en_batch, padding_value=0, batch_first=True)
:對(duì)英文序列進(jìn)行填充,使其長(zhǎng)度一致。zh_batch = nn.utils.rnn.pad_sequence(zh_batch, padding_value=0, batch_first=True)
:對(duì)中文序列進(jìn)行填充,使其長(zhǎng)度一致。return en_batch, zh_batch
:返回填充后的英文和中文批量數(shù)據(jù)。
定義 Seq2Seq模型
Encoder
class Encoder(nn.Module):def __init__(self, input_dim, emb_dim, hid_dim, n_layers, dropout):super().__init__()self.embedding = nn.Embedding(input_dim, emb_dim)self.rnn = nn.GRU(emb_dim, hid_dim, n_layers, dropout=dropout, batch_first=True)self.dropout = nn.Dropout(dropout)def forward(self, src):# src shape: [batch_size, src_len]embedded = self.dropout(self.embedding(src))# embedded shape: [batch_size, src_len, emb_dim]outputs, hidden = self.rnn(embedded)# outputs shape: [batch_size, src_len, hid_dim]# hidden shape: [n_layers, batch_size, hid_dim]return outputs, hidden
- 初始化:
input_dim
:輸入詞匯表的大小。emb_dim
:嵌入層的維度。hid_dim
:隱藏層的維度。n_layers
:RNN的層數(shù)。dropout
:Dropout的概率。
- 前向傳播:
- 輸入
src
的形狀為[batch_size, src_len]
。 - 通過(guò)嵌入層和Dropout層,得到
embedded
,形狀為[batch_size, src_len, emb_dim]
。 - 通過(guò)GRU層,得到
outputs
和hidden
,形狀分別為[batch_size, src_len, hid_dim]
和[n_layers, batch_size, hid_dim]
。
- 輸入
Decoder
class Decoder(nn.Module):def __init__(self, output_dim, emb_dim, hid_dim, n_layers, dropout):super().__init__()self.output_dim = output_dimself.embedding = nn.Embedding(output_dim, emb_dim)self.rnn = nn.GRU(emb_dim, hid_dim, n_layers, dropout=dropout, batch_first=True)self.fc_out = nn.Linear(hid_dim, output_dim)self.dropout = nn.Dropout(dropout)def forward(self, input, hidden):# input shape: [batch_size, 1]# hidden shape: [n_layers, batch_size, hid_dim]embedded = self.dropout(self.embedding(input))# embedded shape: [batch_size, 1, emb_dim]output, hidden = self.rnn(embedded, hidden)# output shape: [batch_size, 1, hid_dim]# hidden shape: [n_layers, batch_size, hid_dim]prediction = self.fc_out(output.squeeze(1))# prediction shape: [batch_size, output_dim]return prediction, hidden
- 初始化:
output_dim
:輸出詞匯表的大小。emb_dim
:嵌入層的維度。hid_dim
:隱藏層的維度。n_layers
:RNN的層數(shù)。dropout
:Dropout的概率。
- 前向傳播:
- 輸入
input
的形狀為[batch_size, 1]
,hidden
的形狀為[n_layers, batch_size, hid_dim]
。 - 通過(guò)嵌入層和Dropout層,得到
embedded
,形狀為[batch_size, 1, emb_dim]
。 - 通過(guò)GRU層,得到
output
和hidden
,形狀分別為[batch_size, 1, hid_dim]
和[n_layers, batch_size, hid_dim]
。 - 通過(guò)全連接層,得到
prediction
,形狀為[batch_size, output_dim]
。
- 輸入
Seq2Seq 類
class Seq2Seq(nn.Module):def __init__(self, encoder, decoder, device):super().__init__()self.encoder = encoderself.decoder = decoderself.device = devicedef forward(self, src, trg, teacher_forcing_ratio=0.5):# src shape: [batch_size, src_len]# trg shape: [batch_size, trg_len]batch_size = src.shape[0]trg_len = trg.shape[1]trg_vocab_size = self.decoder.output_dimoutputs = torch.zeros(batch_size, trg_len, trg_vocab_size).to(self.device)_, hidden = self.encoder(src)input = trg[:, 0].unsqueeze(1) # Start tokenfor t in range(1, trg_len):output, hidden = self.decoder(input, hidden)outputs[:, t, :] = outputteacher_force = random.random() < teacher_forcing_ratiotop1 = output.argmax(1)input = trg[:, t].unsqueeze(1) if teacher_force else top1.unsqueeze(1)return outputs
- 初始化:
encoder
:編碼器實(shí)例。decoder
:解碼器實(shí)例。device
:設(shè)備(CPU或GPU)。
- 前向傳播:
- 輸入
src
的形狀為[batch_size, src_len]
,trg
的形狀為[batch_size, trg_len]
。 - 初始化
outputs
,形狀為[batch_size, trg_len, trg_vocab_size]
。 - 通過(guò)編碼器得到
hidden
。 - 初始化解碼器的輸入為
trg[:, 0].unsqueeze(1)
,即目標(biāo)序列的起始標(biāo)記。 - 循環(huán)解碼目標(biāo)序列的每個(gè)時(shí)間步:
- 通過(guò)解碼器得到
output
和hidden
。 - 將
output
存儲(chǔ)到outputs
中。 - 根據(jù)
teacher_forcing_ratio
決定是否使用教師強(qiáng)制(即使用目標(biāo)序列的下一個(gè)詞作為輸入,還是使用解碼器的預(yù)測(cè)結(jié)果)。
- 通過(guò)解碼器得到
- 輸入
load_terminology_dictionary 函數(shù)
-
函數(shù)定義:
def load_terminology_dictionary(dict_file):
dict_file
: 這是一個(gè)字符串參數(shù),表示包含術(shù)語(yǔ)詞典的文件路徑。
-
初始化術(shù)語(yǔ)詞典:
terminology = {}
- 創(chuàng)建一個(gè)空的字典
terminology
,用于存儲(chǔ)從文件中讀取的術(shù)語(yǔ)。
- 創(chuàng)建一個(gè)空的字典
-
打開(kāi)文件并讀取內(nèi)容:
with open(dict_file, 'r', encoding='utf-8') as f:for line in f:en_term, ch_term = line.strip().split('\t')terminology[en_term] = ch_term
- 使用
with open
語(yǔ)句打開(kāi)文件,確保文件在使用后正確關(guān)閉。 - 文件以只讀模式 (
'r'
) 打開(kāi),并指定編碼為utf-8
。 - 逐行讀取文件內(nèi)容,每行包含一個(gè)英文術(shù)語(yǔ)和對(duì)應(yīng)的中文術(shù)語(yǔ),用制表符 (
\t
) 分隔。 line.strip()
用于去除行末的換行符和其他空白字符。split('\t')
將行按制表符分隔成兩個(gè)部分,分別賦值給en_term
和ch_term
。- 將英文術(shù)語(yǔ)作為鍵,中文術(shù)語(yǔ)作為值,添加到
terminology
字典中。
- 使用
-
返回術(shù)語(yǔ)詞典:
return terminology
- 函數(shù)返回加載后的術(shù)語(yǔ)詞典。
示例用法
假設(shè)有一個(gè)文件 terminology.txt
,內(nèi)容如下:
apple 蘋(píng)果
banana 香蕉
orange 橙子
調(diào)用 load_terminology_dictionary
函數(shù):
terminology = load_terminology_dictionary('terminology.txt')
print(terminology)
輸出結(jié)果將是:
{'apple': '蘋(píng)果', 'banana': '香蕉', 'orange': '橙子'}
train 函數(shù)
def train(model, iterator, optimizer, criterion, clip):
- 定義一個(gè)名為
train
的函數(shù),該函數(shù)接受五個(gè)參數(shù):model
(模型)、iterator
(數(shù)據(jù)迭代器)、optimizer
(優(yōu)化器)、criterion
(損失函數(shù))和clip
(梯度裁剪的閾值)。
model.train()
- 將模型設(shè)置為訓(xùn)練模式。這會(huì)啟用諸如 dropout 和 batch normalization 等訓(xùn)練特有的操作。
epoch_loss = 0
- 初始化
epoch_loss
變量為 0,用于累積整個(gè) epoch 的損失。
for i, (src, trg) in enumerate(iterator):
- 使用
enumerate
遍歷數(shù)據(jù)迭代器iterator
,每次迭代獲取一個(gè)批次的數(shù)據(jù)(src, trg)
,其中src
是源序列,trg
是目標(biāo)序列。
src, trg = src.to(device), trg.to(device)
- 將源序列和目標(biāo)序列移動(dòng)到指定的設(shè)備(如 GPU)上。
optimizer.zero_grad()
- 將優(yōu)化器的梯度清零,以防止梯度累積。
output = model(src, trg)
- 將源序列和目標(biāo)序列輸入模型,得到模型的輸出。
output_dim = output.shape[-1]
- 獲取輸出張量的最后一個(gè)維度的大小,即輸出序列的詞匯表大小。
output = output[:, 1:].contiguous().view(-1, output_dim)
- 去掉輸出序列的第一個(gè)時(shí)間步(通常是起始標(biāo)記),并將剩余部分展平成二維張量,形狀為
(batch_size * (sequence_length - 1), output_dim)
。
trg = trg[:, 1:].contiguous().view(-1)
- 去掉目標(biāo)序列的第一個(gè)時(shí)間步,并將剩余部分展平成一維張量,形狀為
(batch_size * (sequence_length - 1))
。
loss = criterion(output, trg)
- 計(jì)算損失,使用定義的損失函數(shù)
criterion
。
loss.backward()
- 反向傳播,計(jì)算梯度。
torch.nn.utils.clip_grad_norm_(model.parameters(), clip)
- 對(duì)模型的梯度進(jìn)行裁剪,防止梯度爆炸。裁剪的閾值由參數(shù)
clip
指定。
optimizer.step()
- 更新模型的參數(shù)。
epoch_loss += loss.item()
- 將當(dāng)前批次的損失值累加到
epoch_loss
中。
return epoch_loss / len(iterator)
- 返回整個(gè) epoch 的平均損失。
主程序代碼
if __name__ == '__main__':
- 這是一個(gè)常見(jiàn)的Python慣用法,用于判斷當(dāng)前模塊是否是主程序入口。如果是,則執(zhí)行后續(xù)代碼。后同。
start_time = time.time() # 開(kāi)始計(jì)時(shí)
- 記錄程序開(kāi)始執(zhí)行的時(shí)間,用于后續(xù)計(jì)算總運(yùn)行時(shí)間。
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- 檢查是否有可用的CUDA設(shè)備(即GPU),如果有則使用GPU,否則使用CPU。
terminology = load_terminology_dictionary('../dataset/en-zh.dic')
- 加載術(shù)語(yǔ)字典,該字典可能包含特定領(lǐng)域的術(shù)語(yǔ)翻譯。
dataset = TranslationDataset('../dataset/train.txt', terminology=terminology)
- 創(chuàng)建一個(gè)
TranslationDataset
對(duì)象,該對(duì)象用于加載和處理訓(xùn)練數(shù)據(jù)。
N = 1000 # int(len(dataset) * 1) # 或者你可以設(shè)置為數(shù)據(jù)集大小的一定比例,如 int(len(dataset) * 0.1)subset_indices = list(range(N))subset_dataset = Subset(dataset, subset_indices)
- 選擇數(shù)據(jù)集的前1000個(gè)樣本進(jìn)行訓(xùn)練。
subset_indices
是一個(gè)包含前1000個(gè)索引的列表,subset_dataset
是原始數(shù)據(jù)集的一個(gè)子集。
train_loader = DataLoader(subset_dataset, batch_size=32, shuffle=True, collate_fn=collate_fn)
- 創(chuàng)建一個(gè)
DataLoader
對(duì)象,用于批量加載數(shù)據(jù)。batch_size
設(shè)置為32,shuffle
設(shè)置為True
以打亂數(shù)據(jù)順序,collate_fn
是一個(gè)自定義函數(shù),用于處理批次數(shù)據(jù)的拼接。
INPUT_DIM = len(dataset.en_vocab)OUTPUT_DIM = len(dataset.zh_vocab)ENC_EMB_DIM = 256DEC_EMB_DIM = 256HID_DIM = 512N_LAYERS = 2ENC_DROPOUT = 0.5DEC_DROPOUT = 0.5
- 定義模型參數(shù),包括輸入和輸出維度、嵌入維度、隱藏層維度、層數(shù)和 dropout 率。
enc = Encoder(INPUT_DIM, ENC_EMB_DIM, HID_DIM, N_LAYERS, ENC_DROPOUT)dec = Decoder(OUTPUT_DIM, DEC_EMB_DIM, HID_DIM, N_LAYERS, DEC_DROPOUT)model = Seq2Seq(enc, dec, device).to(device)
- 初始化編碼器和解碼器,并將其組合成一個(gè)
Seq2Seq
模型。然后將模型移動(dòng)到指定的設(shè)備(GPU或CPU)。
optimizer = optim.Adam(model.parameters())criterion = nn.CrossEntropyLoss(ignore_index=dataset.zh_word2idx['<pad>'])
- 定義優(yōu)化器和損失函數(shù)。優(yōu)化器使用 Adam,損失函數(shù)使用交叉熵?fù)p失,并忽略目標(biāo)序列中的填充標(biāo)記
<pad>
。
N_EPOCHS = 10CLIP = 1
- 設(shè)置訓(xùn)練的 epoch 數(shù)和梯度裁剪的閾值。
for epoch in range(N_EPOCHS):train_loss = train(model, train_loader, optimizer, criterion, CLIP)print(f'Epoch: {epoch+1:02} | Train Loss: {train_loss:.3f}')
- 進(jìn)行10個(gè) epoch 的訓(xùn)練。每個(gè) epoch 結(jié)束后,打印當(dāng)前 epoch 的訓(xùn)練損失。
torch.save(model.state_dict(), './translation_model_GRU.pth')
- 在所有 epoch 結(jié)束后,保存模型的參數(shù)到文件
translation_model_GRU.pth
。
end_time = time.time() # 結(jié)束計(jì)時(shí)elapsed_time_minute = (end_time - start_time)/60print(f"Total running time: {elapsed_time_minute:.2f} minutes")
- 記錄程序結(jié)束時(shí)間,計(jì)算并打印總運(yùn)行時(shí)間(以分鐘為單位)。
模型評(píng)價(jià)
import torch
from sacrebleu.metrics import BLEU
from typing import List
# 假設(shè)已經(jīng)定義了TranslationDataset, Encoder, Decoder, Seq2Seq類
- 導(dǎo)入必要的庫(kù)和模塊。
torch
用于深度學(xué)習(xí),sacrebleu.metrics.BLEU
用于評(píng)估翻譯質(zhì)量,typing.List
用于類型注解。
load_sentences 函數(shù)
def load_sentences(file_path: str) -> List[str]:with open(file_path, 'r', encoding='utf-8') as f:return [line.strip() for line in f]
- 定義函數(shù)
load_sentences
,用于從文件中加載句子。file_path
是文件路徑,函數(shù)返回一個(gè)包含所有句子的列表。
translate_sentence 函數(shù)
def translate_sentence(sentence: str, model: Seq2Seq, dataset: TranslationDataset, terminology, device: torch.device, max_length: int = 50):
- 定義一個(gè)函數(shù)
translate_sentence
,用于翻譯單個(gè)句子。參數(shù)包括:sentence
: 要翻譯的句子。model
: 預(yù)訓(xùn)練的Seq2Seq
模型。dataset
:TranslationDataset
對(duì)象,包含詞匯表等信息。terminology
: 術(shù)語(yǔ)詞典。device
: 計(jì)算設(shè)備(CPU 或 GPU)。max_length
: 翻譯句子的最大長(zhǎng)度,默認(rèn)為 50。
model.eval()
- 將模型設(shè)置為評(píng)估模式,關(guān)閉 dropout 和 batch normalization 等訓(xùn)練特有的操作。
tokens = dataset.en_tokenizer(sentence)
- 使用
dataset
中的en_tokenizer
對(duì)輸入句子進(jìn)行分詞,得到一個(gè) token 列表。
tensor = torch.LongTensor([dataset.en_word2idx.get(token, dataset.en_word2idx['<sos>']) for token in tokens]).unsqueeze(0).to(device) # [1, seq_len]
- 將 token 列表轉(zhuǎn)換為索引列表,并轉(zhuǎn)換為 PyTorch 張量。如果 token 不在詞匯表中,則使用
<sos>
的索引。然后將張量增加一個(gè)維度并移動(dòng)到指定的設(shè)備。
with torch.no_grad():_, hidden = model.encoder(tensor)
- 關(guān)閉梯度計(jì)算,以節(jié)省內(nèi)存和提高速度。然后使用編碼器對(duì)輸入張量進(jìn)行編碼,得到隱藏狀態(tài)
hidden
。
translated_tokens = []
- 初始化一個(gè)空列表
translated_tokens
,用于存儲(chǔ)翻譯的 token。
input_token = torch.LongTensor([[dataset.zh_word2idx['<sos>']]]).to(device) # [1, 1]
- 初始化解碼器的輸入 token,即
<sos>
的索引,并將其轉(zhuǎn)換為張量并移動(dòng)到指定的設(shè)備。
for _ in range(max_length):
- 開(kāi)始一個(gè)循環(huán),最多迭代
max_length
次。
output, hidden = model.decoder(input_token, hidden)
- 使用解碼器對(duì)當(dāng)前輸入 token 和隱藏狀態(tài)進(jìn)行解碼,得到輸出
output
和新的隱藏狀態(tài)hidden
。
top_token = output.argmax(1)
- 從輸出中選擇概率最高的 token 索引。
translated_token = dataset.zh_vocab[top_token.item()]
- 將索引轉(zhuǎn)換為對(duì)應(yīng)的 token。
if translated_token == '<eos>':break
- 如果翻譯的 token 是
<eos>
,則結(jié)束循環(huán)。
if translated_token in terminology.values():for en_term, ch_term in terminology.items():if translated_token == ch_term:translated_token = en_termbreak
- 如果翻譯的 token 在術(shù)語(yǔ)詞典中,則使用術(shù)語(yǔ)詞典中的對(duì)應(yīng)詞替換。
translated_tokens.append(translated_token)
- 將翻譯的 token 添加到
translated_tokens
列表中。
input_token = top_token.unsqueeze(1) # [1, 1]
- 更新輸入 token 為當(dāng)前選擇的 token 索引。
return ''.join(translated_tokens)
- 將翻譯的 token 列表連接成一個(gè)字符串并返回。
evaluate_bleu 函數(shù)
def evaluate_bleu(model: Seq2Seq, dataset: TranslationDataset, src_file: str, ref_file: str, terminology, device: torch.device):
- 定義一個(gè)函數(shù)
evaluate_bleu
,用于評(píng)估模型的 BLEU 分?jǐn)?shù)。參數(shù)包括:model
: 預(yù)訓(xùn)練的Seq2Seq
模型。dataset
:TranslationDataset
對(duì)象,包含詞匯表等信息。src_file
: 包含源語(yǔ)言句子的文件路徑。ref_file
: 包含參考翻譯句子的文件路徑。terminology
: 術(shù)語(yǔ)詞典。device
: 計(jì)算設(shè)備(CPU 或 GPU)。
model.eval()
- 將模型設(shè)置為評(píng)估模式,關(guān)閉 dropout 和 batch normalization 等訓(xùn)練特有的操作。
src_sentences = load_sentences(src_file)
- 調(diào)用
load_sentences
函數(shù)加載源語(yǔ)言句子,返回一個(gè)包含所有源句子的列表。
ref_sentences = load_sentences(ref_file)
- 調(diào)用
load_sentences
函數(shù)加載參考翻譯句子,返回一個(gè)包含所有參考翻譯句子的列表。
translated_sentences = []
- 初始化一個(gè)空列表
translated_sentences
,用于存儲(chǔ)翻譯的句子。
for src in src_sentences:
- 遍歷源語(yǔ)言句子列表。
translated = translate_sentence(src, model, dataset, terminology, device)
- 調(diào)用
translate_sentence
函數(shù)翻譯當(dāng)前的源句子,返回翻譯后的句子。
translated_sentences.append(translated)
- 將翻譯后的句子添加到
translated_sentences
列表中。
bleu = BLEU()
- 創(chuàng)建一個(gè)
BLEU
對(duì)象,用于計(jì)算 BLEU 分?jǐn)?shù)。
score = bleu.corpus_score(translated_sentences, [ref_sentences])
- 調(diào)用
corpus_score
方法計(jì)算翻譯句子的 BLEU 分?jǐn)?shù)。translated_sentences
是模型生成的翻譯句子列表,[ref_sentences]
是參考翻譯句子列表。
return score
- 返回計(jì)算得到的 BLEU 分?jǐn)?shù)。
主程序
if __name__ == '__main__':
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- 檢查是否有可用的CUDA設(shè)備(即GPU),如果有則使用GPU,否則使用CPU。
terminology = load_terminology_dictionary('../dataset/en-zh.dic')
- 加載術(shù)語(yǔ)詞典,該字典可能包含特定領(lǐng)域的術(shù)語(yǔ)翻譯。
dataset = TranslationDataset('../dataset/train.txt', terminology)
- 創(chuàng)建一個(gè)
TranslationDataset
對(duì)象,該對(duì)象用于加載和處理訓(xùn)練數(shù)據(jù),并傳遞術(shù)語(yǔ)詞典。
INPUT_DIM = len(dataset.en_vocab)OUTPUT_DIM = len(dataset.zh_vocab)ENC_EMB_DIM = 256DEC_EMB_DIM = 256HID_DIM = 512N_LAYERS = 2ENC_DROPOUT = 0.5DEC_DROPOUT = 0.5
- 定義模型參數(shù),包括輸入和輸出維度、嵌入維度、隱藏層維度、層數(shù)和 dropout 率。
enc = Encoder(INPUT_DIM, ENC_EMB_DIM, HID_DIM, N_LAYERS, ENC_DROPOUT)dec = Decoder(OUTPUT_DIM, DEC_EMB_DIM, HID_DIM, N_LAYERS, DEC_DROPOUT)model = Seq2Seq(enc, dec, device).to(device)
- 初始化編碼器和解碼器,并將其組合成一個(gè)
Seq2Seq
模型。然后將模型移動(dòng)到指定的設(shè)備(GPU或CPU)。
model.load_state_dict(torch.load('./translation_model_GRU.pth'))
- 加載預(yù)訓(xùn)練的模型參數(shù)。
bleu_score = evaluate_bleu(model, dataset, '../dataset/dev_en.txt', '../dataset/dev_zh.txt', terminology=terminology, device=device)
- 調(diào)用
evaluate_bleu
函數(shù)評(píng)估模型的 BLEU 分?jǐn)?shù)。傳遞的參數(shù)包括模型、數(shù)據(jù)集、源語(yǔ)言文件路徑、參考翻譯文件路徑、術(shù)語(yǔ)詞典和設(shè)備。
print(f'BLEU-4 score: {bleu_score.score:.2f}')
- 打印評(píng)估得到的 BLEU-4 分?jǐn)?shù),保留兩位小數(shù)。
測(cè)試集上進(jìn)行推理
inference 函數(shù)
def inference(model: Seq2Seq, dataset: TranslationDataset, src_file: str, save_dir: str, terminology, device: torch.device):
- 定義一個(gè)函數(shù)
inference
,用于進(jìn)行模型推理并將結(jié)果保存到文件中。參數(shù)包括:model
: 預(yù)訓(xùn)練的Seq2Seq
模型。dataset
:TranslationDataset
對(duì)象,包含詞匯表等信息。src_file
: 包含源語(yǔ)言句子的文件路徑。save_dir
: 保存翻譯結(jié)果的文件路徑。terminology
: 術(shù)語(yǔ)詞典。device
: 計(jì)算設(shè)備(CPU 或 GPU)。
model.eval()
- 將模型設(shè)置為評(píng)估模式,關(guān)閉 dropout 和 batch normalization 等訓(xùn)練特有的操作。
src_sentences = load_sentences(src_file)
- 調(diào)用
load_sentences
函數(shù)加載源語(yǔ)言句子,返回一個(gè)包含所有源句子的列表。
translated_sentences = []
- 初始化一個(gè)空列表
translated_sentences
,用于存儲(chǔ)翻譯的句子。
for src in src_sentences:
- 遍歷源語(yǔ)言句子列表。
translated = translate_sentence(src, model, dataset, terminology, device)
- 調(diào)用
translate_sentence
函數(shù)翻譯當(dāng)前的源句子,返回翻譯后的句子。
translated_sentences.append(translated)
- 將翻譯后的句子添加到
translated_sentences
列表中。
text = '\n'.join(translated_sentences)
- 將
translated_sentences
列表中的所有句子連接成一個(gè)字符串,每個(gè)句子之間用換行符分隔。
with open(save_dir, 'w', encoding='utf-8') as f:
- 打開(kāi)一個(gè)文件,如果不存在則創(chuàng)建,
'w'
表示寫(xiě)模式,encoding='utf-8'
表示使用 UTF-8 編碼。
f.write(text)
- 將連接后的字符串寫(xiě)入文件。
主程序
if __name__ == '__main__':
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- 檢查是否有可用的CUDA設(shè)備(即GPU),如果有則使用GPU,否則使用CPU。
terminology = load_terminology_dictionary('../dataset/en-zh.dic')
- 加載術(shù)語(yǔ)詞典,該字典可能包含特定領(lǐng)域的術(shù)語(yǔ)翻譯。
dataset = TranslationDataset('../dataset/train.txt', terminology=terminology)
- 創(chuàng)建一個(gè)
TranslationDataset
對(duì)象,該對(duì)象用于加載和處理訓(xùn)練數(shù)據(jù),并傳遞術(shù)語(yǔ)詞典。
INPUT_DIM = len(dataset.en_vocab)OUTPUT_DIM = len(dataset.zh_vocab)ENC_EMB_DIM = 256DEC_EMB_DIM = 256HID_DIM = 512N_LAYERS = 2ENC_DROPOUT = 0.5DEC_DROPOUT = 0.5
- 定義模型參數(shù),包括輸入和輸出維度、嵌入維度、隱藏層維度、層數(shù)和 dropout 率。
enc = Encoder(INPUT_DIM, ENC_EMB_DIM, HID_DIM, N_LAYERS, ENC_DROPOUT)dec = Decoder(OUTPUT_DIM, DEC_EMB_DIM, HID_DIM, N_LAYERS, DEC_DROPOUT)model = Seq2Seq(enc, dec, device).to(device)
- 初始化編碼器和解碼器,并將其組合成一個(gè)
Seq2Seq
模型。然后將模型移動(dòng)到指定的設(shè)備(GPU或CPU)。
model.load_state_dict(torch.load('./translation_model_GRU.pth'))
- 加載預(yù)訓(xùn)練的模型參數(shù)。
save_dir = '../dataset/submit.txt'
- 定義保存翻譯結(jié)果的文件路徑。
inference(model, dataset, src_file="../dataset/test_en.txt", save_dir=save_dir, terminology=terminology, device=device)
- 調(diào)用
inference
函數(shù)進(jìn)行模型推理,并將翻譯結(jié)果保存到指定文件中。傳遞的參數(shù)包括模型、數(shù)據(jù)集、源語(yǔ)言文件路徑、保存路徑、術(shù)語(yǔ)詞典和設(shè)備。
print(f"翻譯完成!文件已保存到{save_dir}")
- 打印翻譯完成的消息,并顯示保存文件的路徑。