Datawhale AI 夏令营_基于术语词典干预的机器翻译挑战赛 .md

基于术语词典干预的机器翻译

在baseline的基础上添加了soft attention,当N=2000时,没有问题,但是一旦增加数据量就会爆显存,还需要找一下问题

完整代码如下

from typing import Listimport torch
import torch.nn as nn
import torch.optim as optim
from keras import device
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 torch.nn.functional as F
import time
from sacrebleu.metrics import BLEU
from tqdm import tqdm# 数据准备
# 修改TranslationDataset类以处理数据
class TranslationDataset(Dataset):def __init__(self, file_name, terminology):self.data = []with open(file_name, 'r', encoding='utf-8') as f:for line in f:en, zh = line.strip().split('\t') # 训练数据en和zh使用制表符分隔\tself.data.append((en, zh))self.terminology = terminology# 创建词汇表,这里一定要将术语词典中的词也包含在词汇表中self.en_tokenizer = get_tokenizer('basic_english')self.zh_tokenizer = list # 使用用字符级分词en_vocab = Counter(self.terminology.keys()) # 确保术语在词汇表中zh_vocab = Counter()for en, zh in self.data:en_vocab.update(self.en_tokenizer(en))zh_vocab.update(self.zh_tokenizer(zh))# 添加术语到词汇表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_word2idx = {word: idx for idx, word in enumerate(self.en_vocab)}self.zh_word2idx = {word: idx for idx, word in enumerate(self.zh_vocab)}def __len__(self):return len(self.data)def __getitem__(self, idx):# 将一条训练数据(en,zh)转化为tensoren, 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>']]).long()zh_tensor = torch.Tensor([self.zh_word2idx.get(word, self.zh_word2idx['<sos>']) for word in self.zh_tokenizer(zh)] + [self.zh_word2idx['<eos>']]).long()return en_tensor, zh_tensor# 术语词典加载
def load_terminology_dictionary(dict_file):terminology = {}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_termreturn terminologydef collate_fn(batch):"""collate_fn 函数通常用于数据加载器(DataLoader), 对批次数据进行处理和填充:param batch::return:"""en_batch, zh_batch = [], []# 遍历批次中的每个样本for en_item, zh_item in batch:en_batch.append(en_item)zh_batch.append(zh_item)# 对英文的中文序列分别进行填充, 0 对应的是 <pad>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_batchclass Encoder(nn.Module):def __init__(self, vocab_size, emb_dim, hidden_dim, num_layers, dropout):super(Encoder, self).__init__()self.hidden_dim = hidden_dimself.embedding = nn.Embedding(vocab_size, emb_dim)self.rnn = nn.GRU(emb_dim, hidden_dim, num_layers, dropout=dropout, batch_first=True)self.dropout = nn.Dropout(dropout)def forward(self, x):# x : [batch_size, seq_len] => [batch_size, seq_len, emb_dim]embedded = self.dropout(self.embedding(x))# outputs : [batch_size, seq_len, hidden_dim]# hidden : [num_layers, batch_size, seq_len]outputs, hidden = self.rnn(embedded)return outputs, hiddenclass Decoder(nn.Module):def __init__(self, vocab_size, emb_dim, hidden_dim, num_layers, dropout):super(Decoder, self).__init__()self.output_dim = vocab_sizeself.hidden_dim = hidden_dimself.embedding = nn.Embedding(self.output_dim, emb_dim)self.rnn = nn.GRU(emb_dim, hidden_dim, num_layers, dropout=dropout, batch_first=True)self.output = nn.Linear(hidden_dim * 2, self.output_dim)self.dropout = nn.Dropout(dropout)def forward(self, x, hidden, context):# x : [batch_size, seq_len] => [batch_size, seq_len, emb_dim]embedded = self.dropout(self.embedding(x))# outputs : [batch_size, seq_len, hidden_dim]_, hidden = self.rnn(embedded, hidden)# print("==============", hidden.shape, context.shape)if hidden.shape[1] == 1:hc = torch.cat((context.squeeze(2), hidden[1]), dim=1)else:hc = torch.cat((context.squeeze(), hidden[1].squeeze()), dim=1)# 由seq_len = 1的 [batch_size, output_dim]pred = self.output(hc)return pred, hiddenclass Seq2Seq(nn.Module):def __init__(self, encoder, decoder, device):super(Seq2Seq, self).__init__()self.encoder = encoderself.decoder = decoderself.device = deviceself.attention = nn.Linear(encoder.hidden_dim, self.decoder.hidden_dim)def forward(self, src, trg, teacher_forcing_ratio=0.5):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)# 获取上下文向量o, hidden = self.encoder(src)input = trg[:, 0].unsqueeze(1) # start tokenfor t in range(1, trg_len):# print(hidden.shape)# print(o.shape)# [batch_size, seq, 1] = [batch_size, seq_len, hidden_dim] @ [batch_size, hidden_dim, 1]attn_prob = torch.matmul(self.attention(o), hidden[1].squeeze().unsqueeze(2))# 计算注意力权重 [batch_size, seq_len, 1]attn_weight = F.softmax(attn_prob, dim=1)# 计算上下文向量 [batch_size,hidden_dim, seq_len ] matmul [batch_size, seq_len, 1]context = torch.matmul(o.permute(0, 2, 1), attn_weight)output, hidden = self.decoder(input, hidden, context)outputs[:, t, :] = outputteacher_force = random.random() < teacher_forcing_ratioresult = output.argmax(dim=1) # [batch_size, 1]input = trg[:, t].unsqueeze(1) if teacher_force else result.detach().unsqueeze(1)return outputsdef train(device, model, iterator, optimizer, criterion, clip):model.train()epoch_loss = 0for i, (src, trg) in tqdm(enumerate(iterator)):src, trg = src.to(device), trg.to(device)optimizer.zero_grad()output = model(src, trg)output_dim = output.shape[-1]output = output[:, 1:].contiguous().view(-1, output_dim)trg = trg[:, 1:].contiguous().view(-1)loss = criterion(output, trg)loss.backward()torch.nn.utils.clip_grad_norm_(model.parameters(), clip)optimizer.step()epoch_loss += loss.item()# 清理显存# del src, trg, output, loss# torch.cuda.empty_cache()return epoch_loss / len(iterator)def load_sentences(filepath: str) -> List[str]:with open(filepath, 'r', encoding='utf-8') as f:return [line.strip() for line in f]# 更新translate_sentences函数以考虑术语词典
def translate_sentence(sentence, model, dataset : TranslationDataset, terminology, device: torch.device, max_len: int = 50 ):model.eval()tokens = dataset.en_tokenizer(sentence)tensor = torch.LongTensor([dataset.en_word2idx.get(token, dataset.en_word2idx['<sos>']) for token in tokens]).unsqueeze(0).to(device) # [1, seq_len]with torch.no_grad():o, hidden = model.encoder(tensor)translated_tokens = []input_token = torch.LongTensor([[dataset.zh_word2idx['<sos>']]]).to(device) # [1,1]for i in range(max_len):# print(hidden.shape)# print("model.attention(o) shape:", model.attention(o).shape)# print("hidden[1] shape before squeeze and unsqueeze:", hidden.shape)# print("hidden[1] shape after squeeze and unsqueeze:", hidden[1].squeeze(0).unsqueeze(2).shape)attn_prob = torch.matmul(model.attention(o), hidden[1].unsqueeze(2))# 计算注意力权重 [batch_size, seq_len, 1]attn_weight = F.softmax(attn_prob, dim=1)# 计算上下文向量 [batch_size,hidden_dim, seq_len ] matmul [batch_size, seq_len, 1]context = torch.matmul(o.permute(0, 2, 1), attn_weight)output, hidden = model.decoder(input_token, hidden, context)result = output.argmax(dim=1)translated_token = dataset.zh_vocab[result.item()]if translated_token == '<eos>':break# 如果翻译的词在术语词典中,则使用术语词典中的词if translated_token in terminology.values():for en_term, ch_term in terminology.items():if translated_token == ch_term:translated_token = en_termtranslated_tokens.append(translated_token)input_token = result.unsqueeze(1)return ''.join(translated_tokens)def evaluate_bleu(model: Seq2Seq, dataset: TranslationDataset,src_file,ref_file,terminology ,device: torch.device):model.eval()src_sentences = load_sentences(src_file)ref_sentences = load_sentences(ref_file)translated_sentences = []for src in src_sentences:translated = translate_sentence(src, model, dataset, terminology, device)translated_sentences.append(translated)bleu = BLEU()score = bleu.corpus_score(translated_sentences, [ref_sentences])return scoredef inference(model: Seq2Seq, dataset: TranslationDataset, src_file: str, save_dir: str, terminology,device: torch.device):model.eval()src_sentences = load_sentences(src_file)translated_sentences = []for src in src_sentences:translated = translate_sentence(src, model, dataset, terminology, device)# print(translated)translated_sentences.append(translated)# print(translated_sentences)# 将列表元素连接成一个字符串,每个元素后换行text = '\n'.join(translated_sentences)# 打开一个文件,如果不存在则创建,'w'表示写模式with open(save_dir, 'w', encoding='utf-8') as f:# 将字符串写入文件f.write(text)# return translated_sentencesif __name__ == '__main__':start_time = time.time()  # 开始计时device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')# terminology = load_terminology_dictionary('../dataset/en-zh.dic')terminology = load_terminology_dictionary('nlp/datasets/fanyi/en-zh.dic')# 加载数据 nlp/datasets/fanyi/en-zh.dicdataset = TranslationDataset('nlp/datasets/fanyi/train.txt', terminology=terminology)# 选择数据集的前N个样本进行训练N = 2000 # 或者你可以设置为数据集大小的一定比例,如 int(len(dataset) * 0.1)subset_indices = list(range(N))subset_dataset = Subset(dataset, subset_indices)train_loader = DataLoader(subset_dataset, batch_size=32, shuffle=True, collate_fn=collate_fn)print(len(dataset))# train_loader = DataLoader(Subset, batch_size=32, shuffle=True, collate_fn=collate_fn)# 定义模型参数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# 初始化模型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)# 打印模型中的所有参数for name, param in model.named_parameters():print(f'Parameter name: {name}')print(f'Parameter size: {param.size()}')print('-------------------------')# 定义优化器和损失函数optimizer = optim.Adam(model.parameters())criterion = nn.CrossEntropyLoss(ignore_index=dataset.zh_word2idx['<pad>'])# 训练模型N_EPOCHS = 50CLIP = 1# for epoch in range(N_EPOCHS):#     train_loss = train(device, model, train_loader, optimizer, criterion, CLIP)#     print(f'Epoch: {epoch + 1:02} | Train Loss: {train_loss:.3f}')# # 在训练循环结束后保存模型# torch.save(model.state_dict(), 'nlp/datasets/fanyi/translation_model_GRU.pth')end_time = time.time()  # 结束计时# 计算并打印运行时间elapsed_time_minute = (end_time - start_time) / 60print(f"Total running time: {elapsed_time_minute:.2f} minutes")# 加载训练好的模型model.load_state_dict(torch.load('nlp/datasets/fanyi/translation_model_GRU.pth'))# 评估BLEU分数bleu_score = evaluate_bleu(model, dataset, 'nlp/datasets/fanyi/dev_en.txt', 'nlp/datasets/fanyi/dev_zh.txt',terminology=terminology, device=device)print(f'BLEU-4 score: {bleu_score.score:.2f}')# 加载训练好的模型model.load_state_dict(torch.load('nlp/datasets/fanyi/translation_model_GRU.pth'))save_dir = 'nlp/datasets/fanyi/submit.txt'inference(model, dataset, src_file="nlp/datasets/fanyi/test_en.txt", save_dir=save_dir, terminology=terminology,device=device)print(f"翻译完成!文件已保存到{save_dir}")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/46294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用harbor作为chart仓库实现内网部署

使用harbor作为chart仓库实现内网部署 制作好的chart包可以传到chart仓库进行共享&#xff0c;chart仓库可以是公有仓库或者使用Harbor搭建的私有仓库。 本文使用的环境信息&#xff1a; rootmaster1:~# kubectl get node NAME STATUS ROLES AGE VERSION…

react antd table拖拽

下载node包 npm install react-resizable -D npm install types/react-resizable --save-dev 定义一个公用组建 ResizableTable.tsx import { useEffect, useState } from "react"; import { Resizable } from "react-resizable"; import "./resize.s…

使用Python + Scrapy + Django构建企业级爬虫平台

引言 在大数据时代&#xff0c;信息就是力量。对于企业而言&#xff0c;掌握行业动态、竞品分析、市场趋势等关键数据&#xff0c;是决策制定的重要依据。然而&#xff0c;手动收集这些信息既费时又低效。因此&#xff0c;自动化数据采集变得至关重要。本文将向你展示如何使用…

专业条码二维码扫描设备和手机二维码扫描软件的区别?

条码二维码技术已广泛应用于我们的日常生活中&#xff0c;从超市结账到公交出行&#xff0c;再到各类活动的入场验证&#xff0c;条码二维码的便捷性不言而喻&#xff0c;而在条码二维码的扫描识别读取过程中&#xff0c;专业扫描读取设备和手机二维码扫描软件成为了两大主要工…

- vuex路由:

vuex vue的状态管理工具(状态就是数据的管理仓库 话语中级语法modules是vuex的高级用法。 react---redux(状态管理工具) vue2--vuex vue3--pinia(小菠萝) 核心概念(是有五个): 1.state:--存放数据 2.getters:计算属性的&#xff0c;通过筛选数组中大于2的&#xff0c;需要…

MySQL表操作(增删改查)

添加字段 ALTER TABLE 表名 ADD 字段名字 类型&#xff08;长度&#xff09;[COMMENT 注释] [自己给当前字段注释命名];修改字段 &#xff08;1&#xff09;仅仅修改指定字段的一些属性&#xff0c;不能重命名 ALTER TABLE 表名 字段名 新数据类型&#xff08;长度);&#x…

ssh升级

文章目录 ssh升级一、解包ssh、ssl二、更新安装ssl三、手动更新手动复制库文件四、创建符号链接五、更新库路径六、验证库文件七、设置库路径环境变量八、配置、编译、安装OpenSSH&#xff1a;意外&#xff1a;缺少 zlib 的开发库解决方法&#xff1a; 九、刷新ssh服务、查看ss…

力扣第九题

回文数 提示&#xff1a; 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 代码展示&#…

用GPT 4o提高效率

**GPT-4o可以通过提高编程效率、优化工作流程、增强文档管理和知识分享等多方面帮助用户提升工作效率**。具体如下&#xff1a; 1. **代码生成与优化** - **快速原型开发**&#xff1a;程序员可以通过向GPT-4o描述需求或功能来生成初步的代码框架或关键函数&#xff0c;从而节省…

TCP流量控制是怎么实现的?

流量控制就是让发送方发送速率不要过快&#xff0c;让接收方来得及接收。利用滑动窗口机制就可以实施流量控制&#xff0c;主要方法就是动态调整发送方和接收方之间数据传输速率。 发送方维护一个窗口&#xff0c;表示可以发送但尚未被确认的数据量。接收方同样维护一个窗口&a…

C基础入门题:石头剪刀布

1.题目描述 石头剪子布&#xff0c;是一种猜拳游戏。起源于中国&#xff0c;然后传到日本、朝鲜等地&#xff0c;随着亚欧贸易的不断发展它传到了欧洲&#xff0c;到了近现代逐渐风靡世界。简单明了的规则&#xff0c;使得石头剪子布没有任何规则漏洞可钻&#xff0c;单次玩法…

网络安全法律框架更新:最新合规要求与企业应对策略

网络安全法律框架的最新更新 近期&#xff0c;中国的网络安全法律框架经历了重要的更新。2022年&#xff0c;《网络安全法》迎来了首次修改&#xff0c;这一修订主要是为了与《数据安全法》和《个人信息保护法》等新实施的法律进行衔接协调&#xff0c;完善法律责任制度&#x…

slf4j日志框架和logback详解

slf4j作用及其实现原理 SLF4J&#xff08;Simple Logging Facade for Java&#xff09;是一种日志框架的抽象层&#xff0c;它并不是一个具体的日志实现&#xff0c;而是一个接口或门面&#xff08;Facade&#xff09;&#xff0c;旨在为各种不同的日志框架提供一个统一的API。…

AI绘画Stable Diffusion 零基础入门 —AI 绘画原理与工具介绍,万字解析AI绘画的使用教程

大家好&#xff0c;我是设计师阿威 想要入门 AI 绘画&#xff0c;首先需要了解它的原理是什么样的。 其实很早就已经有人基于深度学习模型展开了对图像生成的研究了&#xff0c;但在那时&#xff0c;生成的图像分辨率和内容都非常抽象。 直到近两年&#xff0c;AI 产出的图像…

防火墙nat基础实验

一&#xff0c;实验拓扑&#xff1a; 二&#xff0c;实验需求&#xff1a; 1&#xff0c;办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换) 2&#xff0c;分公司设备可以通过总公司的移动链路和电信链路访问到Dmz区的ht…

俄罗斯VK 平台广告投放的注意事项有哪些?

以下是为您制定适合 VK 平台的广告投放策略的一些建议&#xff1a; 市场调研 深入了解俄罗斯市场的需求、趋势和竞争情况。 分析目标受众的兴趣、行为和消费习惯&#xff0c;以确定最有潜力的细分市场。 明确目标 确定具体、可衡量的广告目标&#xff0c;例如增加品牌知名度…

Appium自动化测试系列: 2. 使用Appium启动APP(真机)

历史文章&#xff1a;Appium自动化测试系列: 1. Mac安装配置Appium_mac安装appium-CSDN博客 一、准备工作 1. 安卓测试机打开调试模式&#xff0c;然后使用可以传输数据的数据线连接上你的电脑。注意&#xff1a;你的数据线一定要支持传输数据&#xff0c;有的数据线只支持充…

蔚来汽车:拥抱TiDB,实现数据库性能与稳定性的飞跃

作者&#xff1a; Billdi表弟 原文来源&#xff1a; https://tidb.net/blog/449c3f5b 演讲嘉宾&#xff1a;吴记 蔚来汽车Tidb爱好者 整理编辑&#xff1a;黄漫绅&#xff08;表妹&#xff09;、李仲舒、吴记 本文来自 TiDB 社区合肥站走进蔚来汽车——来自吴记老师的演讲…

java数组之——了解十大排序算法(动画版)

详细的冒泡排序和快速排序请查看文章&#xff1a;java数组之冒泡排序、快速排序-CSDN博客https://blog.csdn.net/weixin_44554794/article/details/140361078 一、插入排序 二、希尔排序 三、选择排序 四、堆排序 五、冒泡排序 六、快速排序 七、归并排序 八、计数排序 九、桶…

【2024_CUMCM】时间序列1

目录 概念 时间序列数据 时期和时点时间序列 数值变换规律 长期趋势T 季节趋势S 循环变动C 不规则变动I 叠加和乘积模型 叠加模型 相互独立 乘积模型 相互影响 注 spss缺失值填补 简单填补 五种填补方法 填补原则 1.随机缺失 2.完全随机缺失 3.非随机缺失…