基于 Seq2Seq 的中英文翻译项目(pytorch)

[复制链接]
发表于 2026-1-13 08:51:16 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
项目简介

本项目旨在使用 PyTorch 构建一个基于 Seq2Seq(编码器-解码器架构)的中英文翻译模子。我们将使用双语句子对的数据举行训练,终极实现一个可以大概将英文句子翻译为中文的模子。项目的紧张步调包罗:

  • 数据预处置惩罚:从数据会合提取英文和中文句子,并举行开端洗濯和生存。
  • 数据加载与分词:将预处置惩罚后的数据加载进内存,举行分词处置惩罚,并构建词汇表。
  • 模子构建:实现 Seq2Seq 模子的编码器息争码器部分。
  • 模子训练与验证:使用训练集对模子举行训练,并使用验证集评估模子性能。
  • 测试与推理:使用训练好的模子举行实际的翻译测试。

Step 1: 数据预处置惩罚

目的

从原始数据会合提取英文和中文句子,并将其转换为模子可以大概使用的格式。
流程


  • 读取文件:从给定的文本文件中读取每一行数据。
  • 提取句子:每一行数据包罗英文和中文句子,我们将其分割并提取出这两部分。
  • 生存处置惩罚后的数据:将处置惩罚后的句子生存为两个单独的文件,一个生存英文句子,另一个生存中文句子。
代码
  1. import pandas as pd
  2. # 加载数据文件并进行预处理
  3. file_path = 'data/cmn.txt'  # 请确保数据文件位于该路径下
  4. # 读取文件并处理每一行,提取英文和中文句子
  5. data = []
  6. with open(file_path, 'r', encoding='utf-8') as file:
  7.     for line in file:
  8.         # 每行数据使用制表符分割,提取英文和中文部分
  9.         parts = line.strip().split('\t')
  10.         if len(parts) >= 2:
  11.             english_sentence = parts[0].strip()
  12.             chinese_sentence = parts[1].strip()
  13.             data.append([english_sentence, chinese_sentence])
  14. # 创建 DataFrame 保存提取的句子
  15. df = pd.DataFrame(data, columns=['English', 'Chinese'])
  16. # 将处理后的英文和中文句子分别保存为两个文件
  17. df['English'].to_csv('data/english_sentences.txt', index=False, header=False)
  18. df['Chinese'].to_csv('data/chinese_sentences.txt', index=False, header=False)
  19. # 显示前几行以验证处理是否正确
  20. print(df.head())
复制代码
输出示例
  1.   English Chinese
  2. 0     Hi.      嗨。
  3. 1     Hi.     你好。
  4. 2    Run!    你跑吧!
  5. 3    Run!    你快跑!
  6. 4   Who?      是谁?
复制代码

Step 2: 数据加载与分词

目的

将预处置惩罚后的数据加载进内存,对每个句子举行分词处置惩罚,并构建英文和中文的词汇表。
流程


  • 界说分词器:英文使用根本的英文分词器,中文接纳字符级分割。
  • 构建词汇表:基于分词后的数据构建词汇表,并添加特殊标记,如 <unk>、<pad>、<bos>、<eos>。
  • 将句子转换为索引序列:将分词后的句子转换为词汇表中的索引序列,预备用于模子的输入。
  • 创建数据集和数据加载器:将处置惩罚后的数据封装成可用于模子训练的数据集和数据加载器。
代码
  1. import torch
  2. from torchtext.data.utils import get_tokenizer
  3. from torchtext.vocab import build_vocab_from_iterator
  4. # 定义英文和中文的分词器
  5. tokenizer_en = get_tokenizer('basic_english')
  6. # 中文分词器:将每个汉字作为一个 token
  7. def tokenizer_zh(text):
  8.     return list(text)
  9. # 构建词汇表函数
  10. def build_vocab(sentences, tokenizer):
  11.     def yield_tokens(sentences):
  12.         for sentence in sentences:
  13.             yield tokenizer(sentence)
  14.     vocab = build_vocab_from_iterator(yield_tokens(sentences), specials=['<unk>', '<pad>', '<bos>', '<eos>'])
  15.     vocab.set_default_index(vocab['<unk>'])
  16.     return vocab
  17. # 从文件中加载句子
  18. with open('data/english_sentences.txt', 'r', encoding='utf-8') as f:
  19.     english_sentences = [line.strip() for line in f]
  20. with open('data/chinese_sentences.txt', 'r', encoding='utf-8') as f:
  21.     chinese_sentences = [line.strip() for line in f]
  22. # 构建词汇表
  23. en_vocab = build_vocab(english_sentences, tokenizer_en)
  24. zh_vocab = build_vocab(chinese_sentences, tokenizer_zh)
  25. print(f'英文词汇表大小:{len(en_vocab)}')
  26. print(f'中文词汇表大小:{len(zh_vocab)}')
  27. # 将句子转换为索引序列,并添加 <bos> 和 <eos>
  28. def process_sentence(sentence, tokenizer, vocab):
  29.     tokens = tokenizer(sentence)
  30.     tokens = ['<bos>'] + tokens + ['<eos>']
  31.     indices = [vocab[token] for token in tokens]
  32.     return indices
  33. # 处理所有句子
  34. en_sequences = [process_sentence(sentence, tokenizer_en, en_vocab) for sentence in english_sentences]
  35. zh_sequences = [process_sentence(sentence, tokenizer_zh, zh_vocab) for sentence in chinese_sentences]
  36. # 示例:查看处理后的索引序列
  37. print("示例英文句子索引序列:", en_sequences[0])
  38. print("示例中文句子索引序列:", zh_sequences[0])
复制代码
创建数据集和数据加载器
  1. from torch.utils.data import Dataset, DataLoader
  2. from torch.nn.utils.rnn import pad_sequence
  3. class TranslationDataset(Dataset):
  4.     def __init__(self, src_sequences, trg_sequences):
  5.         self.src_sequences = src_sequences
  6.         self.trg_sequences = trg_sequences
  7.     def __len__(self):
  8.         return len(self.src_sequences)
  9.     def __getitem__(self, idx):
  10.         return torch.tensor(self.src_sequences[idx]), torch.tensor(self.trg_sequences[idx])
  11. def collate_fn(batch):
  12.     src_batch, trg_batch = [], []
  13.     for src_sample, trg_sample in batch:
  14.         src_batch.append(src_sample)
  15.         trg_batch.append(trg_sample)
  16.     src_batch = pad_sequence(src_batch, padding_value=en_vocab['<pad>'])
  17.     trg_batch = pad_sequence(trg_batch, padding_value=zh_vocab['<pad>'])
  18.     return src_batch, trg_batch
  19. # 创建数据集
  20. dataset = TranslationDataset(en_sequences, zh_sequences)
  21. # 划分训练集和验证集
  22. from sklearn.model_selection import train_test_split
  23. train_data, val_data = train_test_split(dataset, test_size=0.1)
  24. # 创建数据加载器
  25. batch_size = 32
  26. train_dataloader = DataLoader(train_data, batch_size=batch_size, shuffle=True, collate_fn=collate_fn)
  27. val_dataloader = DataLoader(val_data, batch_size=batch_size, shuffle=False, collate_fn=collate_fn)
复制代码

Step 3: Seq2Seq 模子构建

目的

构建一个基于 Seq2Seq 布局的模子,用于序列到序列的翻译使命。Seq2Seq 模子紧张包罗两个部分:

  • 编码器(Encoder):负责吸收输入的英文句子,将其编码为上下文向量。
  • 解码器(Decoder):根据编码器的输出上下文向量,逐字天生中文翻译。
编码器
  1. import torch.nn as nn
  2. class Encoder(nn.Module):
  3.     def __init__(self, input_dim, emb_dim, hid_dim, n_layers, dropout):
  4.         """
  5.         初始化编码器
  6.         :param input_dim: 输入词汇表的大小(英文词汇表大小)
  7.         :param emb_dim: 词嵌入维度
  8.         :param hid_dim: 隐藏层维度
  9.         :param n_layers: LSTM 层数
  10.         :param dropout: Dropout 概率
  11.         """
  12.         super().__init__()
  13.         self.embedding = nn.Embedding(input_dim, emb_dim)
  14.         self.rnn = nn.LSTM(emb_dim, hid_dim, n_layers, dropout=dropout)
  15.         self.dropout = nn.Dropout(dropout)
  16.     def forward(self, src):
  17.         """
  18.         前向传播
  19.         :param src: [src_len, batch_size]
  20.         :return: hidden, cell
  21.         """
  22.         embedded = self.dropout(self.embedding(src))
  23.         outputs, (hidden, cell) = self.rnn(embedded)
  24.         return hidden, cell
复制代码
解码器
  1. class Decoder(nn.Module):
  2.     def __init__(self, output_dim, emb_dim, hid_dim, n_layers, dropout):
  3.         """
  4.         初始化解码器
  5.         :param output_dim: 输出词汇表大小(中文词汇表大小)
  6.         :param emb_dim: 词嵌入维度
  7.         :param hid_dim: 隐藏层维度
  8.         :param n_layers: LSTM 层数
  9.         :param dropout: Dropout 概率
  10.         """
  11.         super().__init__()
  12.         self.output_dim = output_dim
  13.         self.embedding = nn.Embedding(output_dim, emb_dim)
  14.         self.rnn = nn.LSTM(emb_dim, hid_dim, n_layers, dropout=dropout)
  15.         self.fc_out = nn.Linear(hid_dim, output_dim)
  16.         self.dropout = nn.Dropout(dropout)
  17.     def forward(self, input, hidden, cell):
  18.         """
  19.         前向传播
  20.         :param input: [batch_size]
  21.         :param hidden: [n_layers, batch_size, hid_dim]
  22.         :param cell: [n_layers, batch_size, hid_dim]
  23.         :return: prediction, hidden, cell
  24.         """
  25.         input = input.unsqueeze(0)  # [1, batch_size]
  26.         embedded = self.dropout(self.embedding(input))  # [1, batch_size, emb_dim]
  27.         output, (hidden, cell) = self.rnn(embedded, (hidden, cell))
  28.         prediction = self.fc_out(output.squeeze(0))  # [batch_size, output_dim]
  29.         return prediction, hidden, cell
复制代码
Seq2Seq 模子
  1. class Seq2Seq(nn.Module):
  2.     def __init__(self, encoder, decoder, device):
  3.         """
  4.         初始化 Seq2Seq 模型
  5.         :param encoder: 编码器对象
  6.         :param decoder: 解码器对象
  7.         :param device: 设备(CPU 或 GPU)
  8.         """
  9.         super().__init__()
  10.         self.encoder = encoder
  11.         self.decoder = decoder
  12.         self.device = device
  13.     def forward(self, src, trg, teacher_forcing_ratio=0.5):
  14.         """
  15.         前向传播
  16.         :param src: [src_len, batch_size]
  17.         :param trg: [trg_len, batch_size]
  18.         :param teacher_forcing_ratio: 教师强制比率
  19.         :return: outputs, [trg_len, batch_size, output_dim]
  20.         """
  21.         batch_size = src.shape[1]
  22.         trg_len = trg.shape[0]
  23.         trg_vocab_size = self.decoder.output_dim
  24.         # 存储解码器输出
  25.         outputs = torch.zeros(trg_len, batch_size, trg_vocab_size).to(self.device)
  26.         # 编码器输出
  27.         hidden, cell = self.encoder(src)
  28.         # 解码器初始输入为 <bos> token
  29.         input = trg[0, :]  # [batch_size]
  30.         for t in range(1, trg_len):
  31.             # 解码器前向传播
  32.             output, hidden, cell = self.decoder(input, hidden, cell)
  33.             outputs[t] = output
  34.             # 决定是否使用教师强制
  35.             teacher_force = torch.rand(1).item() < teacher_forcing_ratio
  36.             top1 = output.argmax(1)  # [batch_size]
  37.             input = trg[t] if teacher_force else top1
  38.         return outputs
复制代码

Step 4: 模子训练与验证

目的

通过训练集对模子举行训练,并使用验证集评估模子性能。
界说丧失函数和优化器
  1. import torch.optim as optim
  2. device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  3. # 定义模型参数
  4. INPUT_DIM = len(en_vocab)
  5. OUTPUT_DIM = len(zh_vocab)
  6. ENC_EMB_DIM = 256
  7. DEC_EMB_DIM = 256
  8. HID_DIM = 512
  9. N_LAYERS = 2
  10. ENC_DROPOUT = 0.5
  11. DEC_DROPOUT = 0.5
  12. # 初始化模型
  13. enc = Encoder(INPUT_DIM, ENC_EMB_DIM, HID_DIM, N_LAYERS, ENC_DROPOUT)
  14. dec = Decoder(OUTPUT_DIM, DEC_EMB_DIM, HID_DIM, N_LAYERS, DEC_DROPOUT)
  15. model = Seq2Seq(enc, dec, device).to(device)
  16. # 定义损失函数和优化器
  17. optimizer = optim.Adam(model.parameters())
  18. criterion = nn.CrossEntropyLoss(ignore_index=zh_vocab['<pad>'])
复制代码
训练和验证函数
  1. def train(model, dataloader, optimizer, criterion, clip):
  2.     model.train()
  3.     epoch_loss = 0
  4.     for src, trg in dataloader:
  5.         src, trg = src.to(device), trg.to(device)
  6.         optimizer.zero_grad()
  7.         output = model(src, trg)
  8.         # output: [trg_len, batch_size, output_dim]
  9.         # trg: [trg_len, batch_size]
  10.         output_dim = output.shape[-1]
  11.         output = output[1:].view(-1, output_dim)
  12.         trg = trg[1:].reshape(-1)
  13.         loss = criterion(output, trg)
  14.         loss.backward()
  15.         torch.nn.utils.clip_grad_norm_(model.parameters(), clip)
  16.         optimizer.step()
  17.         epoch_loss += loss.item()
  18.     return epoch_loss / len(dataloader)
  19. def evaluate(model, dataloader, criterion):
  20.     model.eval()
  21.     epoch_loss = 0
  22.     with torch.no_grad():
  23.         for src, trg in dataloader:
  24.             src, trg = src.to(device), trg.to(device)
  25.             output = model(src, trg, teacher_forcing_ratio=0)
  26.             output_dim = output.shape[-1]
  27.             output = output[1:].view(-1, output_dim)
  28.             trg = trg[1:].reshape(-1)
  29.             loss = criterion(output, trg)
  30.             epoch_loss += loss.item()
  31.     return epoch_loss / len(dataloader)
复制代码
训练与验证循环
  1. n_epochs = 10
  2. clip = 1
  3. for epoch in range(n_epochs):
  4.     train_loss = train(model, train_dataloader, optimizer, criterion, clip)
  5.     val_loss = evaluate(model, val_dataloader, criterion)
  6.     print(f'Epoch {epoch+1}/{n_epochs}, Train Loss: {train_loss:.3f}, Val Loss: {val_loss:.3f}')
复制代码

Step 5: 测试与推理

目的

使用训练好的模子,继承用户输入的英文句子,并天生对应的中文翻译。
代码
  1. def translate_sentence(sentence, model, en_vocab, zh_vocab, tokenizer_en, max_len=50):
  2.     model.eval()
  3.     tokens = tokenizer_en(sentence)
  4.     tokens = ['<bos>'] + tokens + ['<eos>']
  5.     src_indices = [en_vocab[token] for token in tokens]
  6.     src_tensor = torch.LongTensor(src_indices).unsqueeze(1).to(device)  # [src_len, 1]
  7.     with torch.no_grad():
  8.         hidden, cell = model.encoder(src_tensor)
  9.     trg_indices = [zh_vocab['<bos>']]
  10.     for i in range(max_len):
  11.         trg_tensor = torch.LongTensor([trg_indices[-1]]).to(device)
  12.         with torch.no_grad():
  13.             output, hidden, cell = model.decoder(trg_tensor, hidden, cell)
  14.         pred_token = output.argmax(1).item()
  15.         trg_indices.append(pred_token)
  16.         if pred_token == zh_vocab['<eos>']:
  17.             break
  18.     trg_tokens = [zh_vocab.lookup_token(idx) for idx in trg_indices]
  19.     return ''.join(trg_tokens[1:-1])  # 去除 <bos> 和 <eos>
  20. # 示例测试
  21. input_sentence = "How are you?"
  22. translation = translate_sentence(input_sentence, model, en_vocab, zh_vocab, tokenizer_en)
  23. print(f"英文句子: {input_sentence}")
  24. print(f"中文翻译: {translation}")
复制代码

总结

通过本项目,我们从数据预处置惩罚、分词与词汇表构建,到模子的界说、训练和测试,完备地实现了一个基于 Seq2Seq 模子的中英文翻译体系。该模子可以大概继承用户输入的英文句子,并天生对应的中文翻译。该项目不但加深了我们对 Seq2Seq 模子的明白,也为进一步研究呆板翻译和天然语言处置惩罚技能奠基了底子。
  1. # 基于 Seq2Seq 的中英文翻译模子# 导入须要的库import pandas as pdimport torchimport torch.nn as nnimport torch.optim as optimfrom torchtext.data.utils import get_tokenizerfrom torchtext.vocab import build_vocab_from_iteratorfrom torch.utils.data import Dataset, DataLoaderfrom torch.nn.utils.rnn import pad_sequencefrom sklearn.model_selection import train_test_split# 查抄是否有可用的 GPUdevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')print(f'Using device: {device}')# Step 1: 数据预处置惩罚# 读取原始数据并提取英文和中文句子file_path = 'data/cmn.txt'  # 请确保数据文件位于该路径下# 读取文件并处置惩罚每一行,提取英文和中文句子data = []with open(file_path, 'r', encoding='utf-8') as file:    for line in file:        # 每行数据使用制表符分割,提取英文和中文部分        parts = line.strip().split('\t')        if len(parts) >= 2:            english_sentence = parts[0].strip()            chinese_sentence = parts[1].strip()            data.append([english_sentence, chinese_sentence])# 创建 DataFrame 生存提取的句子df = pd.DataFrame(data, columns=['English', 'Chinese'])# 将处置惩罚后的英文和中文句子分别生存为两个文件df['English'].to_csv('data/english_sentences.txt', index=False, header=False)df['Chinese'].to_csv('data/chinese_sentences.txt', index=False, header=False)# 体现前五行数据print(df.head())# Step 2: 数据加载与分词# 界说英文和中文的分词器tokenizer_en = get_tokenizer('basic_english')# 中文分词器:将每个汉字作为一个 tokendef tokenizer_zh(text):    return list(text)# 构建词汇表的函数def build_vocab(sentences, tokenizer):    """    根据给定的句子列表和分词器构建词汇表。    :param sentences: 句子列表    :param tokenizer: 分词器函数    :return: 词汇表对象    """    def yield_tokens(sentences):        for sentence in sentences:            yield tokenizer(sentence)    vocab = build_vocab_from_iterator(yield_tokens(sentences), specials=['<unk>', '<pad>', '<bos>', '<eos>'])    vocab.set_default_index(vocab['<unk>'])  # 设置默认索引为 <unk>    return vocab# 从文件中加载句子with open('data/english_sentences.txt', 'r', encoding='utf-8') as f:    english_sentences = [line.strip() for line in f]with open('data/chinese_sentences.txt', 'r', encoding='utf-8') as f:    chinese_sentences = [line.strip() for line in f]# 构建英文和中文的词汇表en_vocab = build_vocab(english_sentences, tokenizer_en)zh_vocab = build_vocab(chinese_sentences, tokenizer_zh)print(f'英文词汇表巨细:{len(en_vocab)}')print(f'中文词汇表巨细:{len(zh_vocab)}')# 界说将句子转换为索引序列的函数def process_sentence(sentence, tokenizer, vocab):    """    将句子转换为索引序列,并添加 <bos> 和 <eos>    :param sentence: 输入句子    :param tokenizer: 分词器函数    :param vocab: 对应的词汇表    :return: 索引序列    """    tokens = tokenizer(sentence)    tokens = ['<bos>'] + tokens + ['<eos>']    indices = [vocab[token] for token in tokens]    return indices# 将全部句子转换为索引序列en_sequences = [process_sentence(sentence, tokenizer_en, en_vocab) for sentence in english_sentences]zh_sequences = [process_sentence(sentence, tokenizer_zh, zh_vocab) for sentence in chinese_sentences]# 查察示例句子的索引序列print("示例英文句子索引序列:", en_sequences[0])print("示例中文句子索引序列:", zh_sequences[0])# 创建数据集和数据加载器class TranslationDataset(Dataset):    def __init__(self, src_sequences, trg_sequences):        self.src_sequences = src_sequences        self.trg_sequences = trg_sequences    def __len__(self):        return len(self.src_sequences)    def __getitem__(self, idx):        return torch.tensor(self.src_sequences[idx]), torch.tensor(self.trg_sequences[idx])def collate_fn(batch):    """    自界说的 collate_fn,用于将批次中的样本举行添补对齐    """    src_batch, trg_batch = [], []    for src_sample, trg_sample in batch:        src_batch.append(src_sample)        trg_batch.append(trg_sample)    src_batch = pad_sequence(src_batch, padding_value=en_vocab['<pad>'])    trg_batch = pad_sequence(trg_batch, padding_value=zh_vocab['<pad>'])    return src_batch, trg_batch# 创建数据集对象dataset = TranslationDataset(en_sequences, zh_sequences)# 分别训练集和验证集train_data, val_data = train_test_split(dataset, test_size=0.1)# 创建数据加载器batch_size = 32train_dataloader = DataLoader(train_data, batch_size=batch_size, shuffle=True, collate_fn=collate_fn)val_dataloader = DataLoader(val_data, batch_size=batch_size, shuffle=False, collate_fn=collate_fn)# Step 3: Seq2Seq 模子构建# 界说编码器class Encoder(nn.Module):    def __init__(self, input_dim, emb_dim, hid_dim, n_layers, dropout):        """        初始化编码器        :param input_dim: 输入词汇表的巨细(英文词汇表巨细)        :param emb_dim: 词嵌入维度        :param hid_dim: 隐蔽层维度        :param n_layers: LSTM 层数        :param dropout: Dropout 概率        """        super().__init__()        self.embedding = nn.Embedding(input_dim, emb_dim)        self.rnn = nn.LSTM(emb_dim, hid_dim, n_layers, dropout=dropout)        self.dropout = nn.Dropout(dropout)    def forward(self, src):        """        前向传播        :param src: [src_len, batch_size]        :return: hidden, cell        """        embedded = self.dropout(self.embedding(src))  # [src_len, batch_size, emb_dim]        outputs, (hidden, cell) = self.rnn(embedded)  # outputs: [src_len, batch_size, hid_dim]        return hidden, cell  # hidden/cell: [n_layers, batch_size, hid_dim]# 界说解码器class Decoder(nn.Module):    def __init__(self, output_dim, emb_dim, hid_dim, n_layers, dropout):        """        初始化解码器        :param output_dim: 输出词汇表巨细(中文词汇表巨细)        :param emb_dim: 词嵌入维度        :param hid_dim: 隐蔽层维度        :param n_layers: LSTM 层数        :param dropout: Dropout 概率        """        super().__init__()        self.output_dim = output_dim        self.embedding = nn.Embedding(output_dim, emb_dim)        self.rnn = nn.LSTM(emb_dim, hid_dim, n_layers, dropout=dropout)        self.fc_out = nn.Linear(hid_dim, output_dim)        self.dropout = nn.Dropout(dropout)    def forward(self, input, hidden, cell):        """        前向传播        :param input: [batch_size]        :param hidden: [n_layers, batch_size, hid_dim]        :param cell: [n_layers, batch_size, hid_dim]        :return: prediction, hidden, cell        """        input = input.unsqueeze(0)  # [1, batch_size]        embedded = self.dropout(self.embedding(input))  # [1, batch_size, emb_dim]        output, (hidden, cell) = self.rnn(embedded, (hidden, cell))  # output: [1, batch_size, hid_dim]        prediction = self.fc_out(output.squeeze(0))  # [batch_size, output_dim]        return prediction, hidden, cell# 界说 Seq2Seq 模子class Seq2Seq(nn.Module):
  2.     def __init__(self, encoder, decoder, device):
  3.         """
  4.         初始化 Seq2Seq 模型
  5.         :param encoder: 编码器对象
  6.         :param decoder: 解码器对象
  7.         :param device: 设备(CPU 或 GPU)
  8.         """
  9.         super().__init__()
  10.         self.encoder = encoder
  11.         self.decoder = decoder
  12.         self.device = device
  13.     def forward(self, src, trg, teacher_forcing_ratio=0.5):
  14.         """
  15.         前向传播
  16.         :param src: [src_len, batch_size]
  17.         :param trg: [trg_len, batch_size]
  18.         :param teacher_forcing_ratio: 教师强制比率
  19.         :return: outputs, [trg_len, batch_size, output_dim]
  20.         """
  21.         batch_size = src.shape[1]
  22.         trg_len = trg.shape[0]
  23.         trg_vocab_size = self.decoder.output_dim
  24.         # 存储解码器输出
  25.         outputs = torch.zeros(trg_len, batch_size, trg_vocab_size).to(self.device)
  26.         # 编码器输出
  27.         hidden, cell = self.encoder(src)
  28.         # 解码器初始输入为 <bos> token
  29.         input = trg[0, :]  # [batch_size]
  30.         for t in range(1, trg_len):
  31.             # 解码器前向传播
  32.             output, hidden, cell = self.decoder(input, hidden, cell)
  33.             outputs[t] = output
  34.             # 决定是否使用教师强制
  35.             teacher_force = torch.rand(1).item() < teacher_forcing_ratio
  36.             top1 = output.argmax(1)  # [batch_size]
  37.             input = trg[t] if teacher_force else top1
  38.         return outputs
  39. # 初始化模子参数INPUT_DIM = len(en_vocab)OUTPUT_DIM = len(zh_vocab)ENC_EMB_DIM = 256DEC_EMB_DIM = 256HID_DIM = 512N_LAYERS = 2ENC_DROPOUT = 0.5DEC_DROPOUT = 0.5# 实例化编码器、解码器和 Seq2Seq 模子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)# 初始化模子参数def init_weights(m):    for name, param in m.named_parameters():        nn.init.uniform_(param.data, -0.08, 0.08)model.apply(init_weights)# 界说丧失函数和优化器optimizer = optim.Adam(model.parameters())criterion = nn.CrossEntropyLoss(ignore_index=zh_vocab['<pad>'])# Step 4: 模子训练与验证# 界说训练函数def train(model, dataloader, optimizer, criterion, clip):    model.train()    epoch_loss = 0    for src, trg in dataloader:        src, trg = src.to(device), trg.to(device)        optimizer.zero_grad()        output = model(src, trg)        # output: [trg_len, batch_size, output_dim]        # trg: [trg_len, batch_size]        output_dim = output.shape[-1]        output = output[1:].view(-1, output_dim)  # 去掉 <bos>        trg = trg[1:].reshape(-1)        loss = criterion(output, trg)        loss.backward()        torch.nn.utils.clip_grad_norm_(model.parameters(), clip)  # 防止梯度爆炸        optimizer.step()        epoch_loss += loss.item()    return epoch_loss / len(dataloader)# 界说验证函数def evaluate(model, dataloader, criterion):    model.eval()    epoch_loss = 0    with torch.no_grad():        for src, trg in dataloader:            src, trg = src.to(device), trg.to(device)            output = model(src, trg, teacher_forcing_ratio=0)  # 关闭西席欺压            output_dim = output.shape[-1]            output = output[1:].view(-1, output_dim)  # 去掉 <bos>            trg = trg[1:].reshape(-1)            loss = criterion(output, trg)            epoch_loss += loss.item()    return epoch_loss / len(dataloader)# 开始训练模子n_epochs = 10
  40. clip = 1
  41. for epoch in range(n_epochs):
  42.     train_loss = train(model, train_dataloader, optimizer, criterion, clip)
  43.     val_loss = evaluate(model, val_dataloader, criterion)
  44.     print(f'Epoch {epoch+1}/{n_epochs}, Train Loss: {train_loss:.3f}, Val Loss: {val_loss:.3f}')
  45. # Step 5: 测试与推理# 界说翻译函数def translate_sentence(sentence, model, en_vocab, zh_vocab, tokenizer_en, max_len=50):    """    翻译英文句子为中文    :param sentence: 英文句子(字符串)    :param model: 训练好的 Seq2Seq 模子    :param en_vocab: 英文词汇表    :param zh_vocab: 中文词汇表    :param tokenizer_en: 英文分词器    :param max_len: 最大翻译长度    :return: 中文翻译(字符串)    """    model.eval()    tokens = tokenizer_en(sentence)    tokens = ['<bos>'] + tokens + ['<eos>']    src_indices = [en_vocab[token] for token in tokens]    src_tensor = torch.LongTensor(src_indices).unsqueeze(1).to(device)  # [src_len, 1]    with torch.no_grad():        hidden, cell = model.encoder(src_tensor)    trg_indices = [zh_vocab['<bos>']]    for i in range(max_len):        trg_tensor = torch.LongTensor([trg_indices[-1]]).to(device)        with torch.no_grad():            output, hidden, cell = model.decoder(trg_tensor, hidden, cell)        pred_token = output.argmax(1).item()        trg_indices.append(pred_token)        if pred_token == zh_vocab['<eos>']:            break    trg_tokens = [zh_vocab.lookup_token(idx) for idx in trg_indices]    return ''.join(trg_tokens[1:-1])  # 去除 <bos> 和 <eos># 示例测试input_sentence = "How are you?"translation = translate_sentence(input_sentence, model, en_vocab, zh_vocab, tokenizer_en)print(f"英文句子: {input_sentence}")print(f"中文翻译: {translation}")# 您可以在此处输入其他英文句子举行测试while True:    input_sentence = input("请输入英文句子(输入 'quit' 退出):")    if input_sentence.lower() == 'quit':        break    translation = translate_sentence(input_sentence, model, en_vocab, zh_vocab, tokenizer_en)    print(f"中文翻译: {translation}")
复制代码
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表