【Datawhale AI 夏令营】讯飞“基于术语词典干预的机器翻译挑战赛”

news2024/9/19 13:55:16

背景

机器翻译具有悠长的发展历史,目前主流的机器翻译方法为神经网络翻译,如LSTM和transformer。在特定领域或行业中,由于机器翻译难以保证术语的一致性,导致翻译效果还不够理想。对于术语名词、人名地名等机器翻译不准确的结果,可以通过术语词典进行纠正,避免了混淆或歧义,最大限度提高翻译质量。

任务

基于术语词典干预的机器翻译挑战赛选择以英文为源语言,中文为目标语言的机器翻译。本次大赛除英文到中文的双语数据,还提供英中对照的术语词典。参赛队伍需要基于提供的训练数据样本从多语言机器翻译模型的构建与训练,并基于测试集以及术语词典,提供最终的翻译结果。

Baseline代码解读

首先导入相应的包

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

随后定义数据集、Decoder类、Encoder类、Seq2seq类

# 定义数据集类
# 修改TranslationDataset类以处理术语
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))
        
        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 = 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 collate_fn(batch):
    en_batch, zh_batch = [], []
    for en_item, zh_item in batch:
        en_batch.append(en_item)
        zh_batch.append(zh_item)
    
    # 对英文和中文序列分别进行填充
    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
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

class Decoder(nn.Module):
    def __init__(self, output_dim, emb_dim, hid_dim, n_layers, dropout):
        super().__init__()
        self.output_dim = output_dim
        self.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

class Seq2Seq(nn.Module):
    def __init__(self, encoder, decoder, device):
        super().__init__()
        self.encoder = encoder
        self.decoder = decoder
        self.device = device

    def 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_dim

        outputs = torch.zeros(batch_size, trg_len, trg_vocab_size).to(self.device)
        
        _, hidden = self.encoder(src)
        
        input = trg[:, 0].unsqueeze(1)  # Start token
        
        for t in range(1, trg_len):
            output, hidden = self.decoder(input, hidden)
            outputs[:, t, :] = output
            teacher_force = random.random() < teacher_forcing_ratio
            top1 = output.argmax(1)
            input = trg[:, t].unsqueeze(1) if teacher_force else top1.unsqueeze(1)

        return outputs

增加术语词典

# 新增术语词典加载部分
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_term
    return terminology

训练模型

def train(model, iterator, optimizer, criterion, clip):
    model.train()
    epoch_loss = 0
    for i, (src, trg) in 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()
    return epoch_loss / len(iterator)

主函数,设置批次大小和数据量

# 主函数
if __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('../dataset/en-zh.dic')

    # 加载数据
    dataset = TranslationDataset('../dataset/train.txt',terminology = terminology)
    # 选择数据集的前N个样本进行训练
    N = 1000  #int(len(dataset) * 1)  # 或者你可以设置为数据集大小的一定比例,如 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)

    # 定义模型参数
    INPUT_DIM = len(dataset.en_vocab)
    OUTPUT_DIM = len(dataset.zh_vocab)
    ENC_EMB_DIM = 256
    DEC_EMB_DIM = 256
    HID_DIM = 512
    N_LAYERS = 2
    ENC_DROPOUT = 0.5
    DEC_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)

    # 定义优化器和损失函数
    optimizer = optim.Adam(model.parameters())
    criterion = nn.CrossEntropyLoss(ignore_index=dataset.zh_word2idx['<pad>'])

    # 训练模型
    N_EPOCHS = 10
    CLIP = 1

    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}')
        
    # 在训练循环结束后保存模型
    torch.save(model.state_dict(), './translation_model_GRU.pth')
    
    end_time = time.time()  # 结束计时

    # 计算并打印运行时间
    elapsed_time_minute = (end_time - start_time)/60
    print(f"Total running time: {elapsed_time_minute:.2f} minutes")

由于没有对代码进行任何修改,所以效果并不好

之后尝试修改N以及NEPOCH参数,来降低损失,从而提高分数

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

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

相关文章

PyTorch复现PointNet++——模型训练+模型测试

本博文主要实现对PointNet源码进行调试&#xff0c;训练可视化测试。 一、下载源码和数据集 论文&#xff1a;PointNet: Deep Hierarchical Feature Learning on Point Sets in a Metric Space GitHub源码&#xff1a;Pointnet2_pytorch 数据集包括三种&#xff1a;分类、零部…

修改留言板

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>备忘录</title><!-- <link rel"…

[Spring] Spring Web MVC基础理论

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

如何从 PDF 中删除背景

您是否曾经收到过充满分散注意力背景的扫描 PDF 文档&#xff1f;也许是带有繁忙水印的旧收据或背景光线不均匀的扫描文档。虽然这些背景可能看起来没什么大不了的&#xff0c;但它们会使您的工作空间变得混乱&#xff0c;并使您难以专注于重要信息。轻松删除这些不需要的元素并…

嵌入式基础 硬件接口汇总

在此收集整理嵌入式通信中常见的接口协议&#xff0c;它们具有一定的通用性&#xff0c;在今后的开发中会反复遇到。 包括但不限于以下类别&#xff08;逐步完善中…&#xff09;&#xff1a; GPIOUARTSPII2CUSBEthernetNAND Flash类SDRAM类&#xff08;ram-like&#xff09;LC…

机器学习——随机森林(学习笔记)

目录 一、基础认识 1. 集成算法介绍 2. 集成算法种类 二、sklearn中的随机森林 1. ensemble.RandomForestClassifier &#xff08;随机森林分类&#xff09; &#xff08;1&#xff09;基本参数 &#xff08;2&#xff09;基本属性 &#xff08;3&#xff09;基本接口 …

【Linux】centos7安装PHP7.4报错:libzip版本过低

问题描述 configure: error: Package requirements (libzip > 0.11 libzip ! 1.3.1 libzip ! 1.7.0) were not met: checking for libzip > 0.11 libzip ! 1.3.1 libzip ! 1.7.0... no configure: error: Package requirements (libzip > 0.11 libzip ! 1.3.1 libzi…

DAMA学习笔记(五)-数据存储和操作

1.引言 数据存储与操作包括对存储数据的设计、实施和支持&#xff0c;最大化实现数据资源的价值&#xff0c;贯穿于数据创建/获取到处置的整个生命周期。 数据存储与操作包含两个子活动&#xff08;图6-1&#xff09;。 图6-1 语境关系图&#xff1a;数据存储与操作 (1) 数据库…

分布式系统—Ceph块存储系统(RBD接口)

目录 一、服务端操作 1 创建一个名为 rbd-xy101 的专门用于 RBD 的存储池 2 将存储池转换为 RBD 模式 3 初始化存储池 4 创建镜像 5 管理镜像 6.Linux客户端使用 在管理节点创建并授权一个用户可访问指定的 RBD 存储池 ​编辑修改RBD镜像特性&#xff0c;CentOS7默认情…

英特尔CPU研发团队繁忙的一天

早晨&#xff1a;准备与启动 7:00 AM - 起床与准备 研发团队的工程师们早早起床&#xff0c;快速洗漱并享用健康的早餐。部分工程师会进行晨间锻炼&#xff0c;保持头脑清醒和身体活力。 8:00 AM - 到达办公室 工程师们来到位于硅谷的英特尔总部&#xff0c;进入研发中心。…

Open-TeleVision——通过VR沉浸式感受人形机器人视野的远程操作

前言 7.3日&#xff0c;我司大模型机器人(具身智能)线下营群里的一学员发了《Open-TeleVision: Teleoperation with Immersive Active Visual Feedback》这篇论文的链接&#xff0c;我当时快速看了一遍&#xff0c;还是有价值的一个工作(其有受mobile aloha工作的启发)&#x…

MT6816磁编码IC在工控机器人中的应用

在现代工业自动化领域&#xff0c;高精度的位置检测和控制技术对于机器人系统的稳定运行至关重要。MT6816磁编码IC作为一款先进的磁传感器解决方案&#xff0c;以其卓越的性能和稳定性&#xff0c;在工控机器人中得到了广泛的应用。本文将详细探讨MT6816磁编码IC在工控机器人中…

git常用命令及git分支

git常用命令及git分支 git常用命令设置用户签名初始化本地库查看本地库状态将文件添加到暂存区提交到本地库查看历史记录版本穿梭 git分支什么是分支分支的好处分支的操作查看分支创建分支切换分支删除分支合并分支合并冲突 git常用命令 设置用户签名 //设置用户签名 git con…

Golang:数据科学领域中的高性能并发编程新星

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 并发性能的卓越表现📝 系统级工具的便捷性📝 语言设计的简洁性📝 强类型系统的严格性📝 版本兼容性的稳定性📝 内置工具的全面性⚓️ 相关链接 ⚓️📖 介绍 📖 在数据科学和机器学习的广阔天地…

音视频开发—使用FFmpeg从纯H264码流中提取图片 C语言实现

文章目录 1.H264码流文件解码流程关键流程详细解码流程详细步骤解析 2.JPEG编码流程详细编码流程详细步骤解析 3.完整示例代码4.效果展示 从纯H.264码流中提取图片的过程包括解码和JPEG编码两个主要步骤&#xff0c;以下是详细阐述 1.H264码流文件解码流程 关键流程 查找编解…

微信小程序---分包加载

一、分包加载 1. 什么是分包加载 什么是分包加载 ❓ 小程序的代码通常是由许多页面、组件以及资源等组成&#xff0c;随着小程序功能的增加&#xff0c;代码量也会逐渐增加&#xff0c;体积过大就会导致用户打开速度变慢&#xff0c;影响用户的使用体验。 分包加载是一种小…

线性代数|机器学习-P23梯度下降

文章目录 1. 梯度下降[线搜索方法]1.1 线搜索方法&#xff0c;运用一阶导数信息1.2 经典牛顿方法&#xff0c;运用二阶导数信息 2. hessian矩阵和凸函数2.1 实对称矩阵函数求导2.2. 线性函数求导 3. 无约束条件下的最值问题4. 正则化4.1 定义4.2 性质 5. 回溯线性搜索法 1. 梯度…

nodejs模板引擎(一)

在 Node.js 中使用模板引擎可以让您更轻松地生成动态 HTML 页面&#xff0c;通过将静态模板与动态数据结合&#xff0c;您可以创建可维护且易于扩展的 Web 应用程序。以下是一个使用 Express 框架和 EJS 模板引擎的基本示例&#xff1a; 安装必要的依赖&#xff1a; 首先&#…

(四)stm32之通信协议

一.串口通信 1、全双工、半双工、单工 单工:只能一个人传输,只能向一个方向传输 半双工:只能一个人传输,可以多个方向传输 全双工:多方传输,多个方向传输 2、同步通信、一步通信 异步通信:双方时钟可以不同步,发送的信息封装(加上起始位、停止位)实现同步,效率低,…

生成式AI推动药物发现革命:加速开发,降低成本

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…