Navigation

    Gpushare.com

    • Register
    • Login
    • Search
    • Popular
    • Categories
    • Recent
    • Tags
    1. Home
    2. 173****5160
    • Profile
    • Following 0
    • Followers 0
    • Topics 5
    • Posts 6
    • Best 5
    • Groups 0

    173****5160

    @173****5160

    10
    Reputation
    5
    Profile views
    6
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    173****5160 Unfollow Follow

    Best posts made by 173****5160

    • [低资源机器翻译综述]:A Survey on Low-Resource Neural Machine Translation

      摘要

      神经机器翻译效果非常好,但需要大量的平行语料,因此有了低资源翻译的研究。
      本文按照按数据的利用对低资源翻译分为3类:

      1. 利用单语数据
      2. 利用辅助语言
      3. 利用多模态数据

      01d786ae-0fe1-4346-a89f-abec8bfdd27d-image.png

      结论和未来方向

      目前还有如下开放问题:

      1. 在多语言迁移学习中,尚不知道应该用多少语言、哪些语言。
      2. 在迁移学习中如何处理未见过语言的词表
      3. 如何高效选择数轴语言
      4. 双语词典非常有用且易得,目前的研究主要用在源语言和目标语言上,如何用在多语言迁移学习中的低资源和辅助语言上
      5. 考虑到多模态数据,语音有提升翻译性能的潜力,同时也有许多限制,比如有同音异字
      6. 目前在低资源翻译上取得成功的方法,或者有大量单语语料,或者有相似的富资源语言。如果两个都没有怎么办,如阿迪格语和锡伯语。

      2.利用单语数据

      ba212708-5447-4b29-9e46-fb9a64a08a6f-image.png

      2.1 回译、前向翻译

      回译:用tgt2src的反向翻译模型将目标语言的单语语料t转换为源语言,从而得到伪平行数据Bp(tgt2src(t),t)。
      前向翻译:相反,用src2tgt的正向翻译模型将源语言的单语语料s转换为目标语言,从而得到伪平行数据Bp’(s, src2tgt(s))。
      将产生的伪数据Bp, Bp’和真的平行语料Dp混合后训练正向模型有助于性能提升。
      除了使用术搜索生成伪数据外,还有许多方法:

      (1)根据输出概率分布随机采样
      (2)在源语言添加噪声,再结合术搜索生成
      (3)对术搜索生成的句子预先添加标签
      随机采样和加噪声只在富资源语言上奏效,而第三种预添加标签在富、低资源翻译上都表现最好。除此之外,在低资源翻译上,将目标语言拷贝到源语言也能进一步提升翻译质量。

      2.2 双向联合训练

      (1)考虑到源语言和目标语言都很稀缺的情况,可以使用对偶学习,将源语言x经前向模型得到y’,再输入反向模型回译成x’,优化x和x’的重建损失。后面有人提出multi-agent进一步提升对偶学习。,
      (2)直观上,更好的回译模型带来更好的伪数据,从而训练出更好的翻译系统。使用迭代回译可以重复执行回译、训练的过程,从而使模型生成越来越高质量的句子,得到更好的NMT系统,流程如下图:
      556c2cb0-3b6d-41df-aa20-6febf9db3626-image.png

      2.3无监督NMT

      为处理零资源翻译的场景,常用的步骤包含两个部分:
      (1)双语对齐,使模型能对齐两种语言:
      a.双语词嵌入
      b.降噪自编码器
      c.无监督统计机器翻译
      d.语言模型预训练
      (2)翻译提升,通过迭代学习提升翻译质量:
      a.迭代回译,见2.2
      b.过滤低质量的伪数据
      c.Loss种加正则,防止训练时遗忘双语嵌入
      d.同时用统计、神经机器翻译模型进行回译

      2.4语言模型预训练

      预训练语言模型能提升对语言的理解和生成能力,而NMT同时需要这两种能力,按是否联合训练编码器和解码器分为两类:
      (1)分离训练:如XLM
      (2)联合训练:如MASS,Bart,T5

      2.5利用相似语料

      相似语料即涉及相同实体的不同语言单语语料,可以从中挖掘隐含的平行语料。如LASER。

      2.6利用双语词典增强

      (1)用于稀有词翻译
      (2)逐词翻译
      (3)基于词典,缩小源语言和目标语言之间嵌入空间的差距

      2.7 小结

      以上方法可以组合使用,如回译和联合训练

      3. 利用辅助语言

      156eae12-d0f9-4378-8369-cd0777c0c157-image.png

      3.1 多语言训练:

      低资源语言对与其他语言对在一个模型中联合训练
      优点:
      (1)较训练多个模型,多语言训练显著降低训练时间,且容易维护
      (2)低资源语言可以受益于富资源语言
      (3)多语言模型有潜力做到零资源翻译
      相关工作可被分为:
      (1)参数共享(不共享、全部共享、部分共享)
      (2)针对低资源语言的设计
      a.辅助语言选择,尽量选择同一语系的富资源语言
      b.训练样本平衡,用基于温度的方法平衡富、低资源语言,使得模型不再偏好富资源语言
      c.辅助语言词重排序:预先对辅助语言重排词的顺序再进行翻译
      d.辅助语言的单语数据:用回译、跨语言预训练、元学习、无监督等方法提升低资源语言模型
      (3)零资源翻译
      假设模型学过x和英文的双向翻译,y和英文的双向翻译,即使模型没见过x和y的平行语料,模型也能进行x和y的双向翻译。

      3.2 迁移学习:

      即先训练通常包含富资源语言对的父母NMT模型,然后微调低资源语言对。
      共享词汇表不适用于将预先训练的父模型迁移到词汇表中有未见过文字的语言。为了解决这一问题,Kim等人提出学习未见语言和双语父模型的嵌入的跨语言线性映射。

      3.3 枢轴翻译:

      选择一种或多种枢轴语言作为源语言和目标语言之间的桥梁,利用源-枢轴和枢轴-目标数据来帮助源目标语言的翻译。有如下三种方式:
      (1)直接结合源-枢轴和枢轴-目标模型,逐个翻译
      (2)使用源-枢轴和枢轴-目标模型生成伪数据,用来训练源-目标模型
      (3)使用源-枢轴和枢轴-目标模型的参数,进行从源到目标语言的迁移学习

      4.利用多模态数据

      目前,图像-文本并行数据在NMT上的应用是有限的,因为这种图像-文本数据对于低资源语言来说总是很难收集。建立新的图像-文本数据集的一个可能的数据源是网站上的图像和相应的标题。
      对于只有语音而没有文本的语言,可以利用语音数据来进行翻译。

      5.数据集

      4fffeb5c-eaa7-46ed-9cd3-939124608219-image.png

      个人总结

      接下来我可以针对迁移学习的词表映射、多语言模型的部分参数共享、对偶学习、元学习这几个方面继续研读。

      参考

      A Survey on Low-Resource Neural Machine Translation

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • NAG优化器

      最近在看fairseq源码时发现NAG优化器 (Nesterov Accelerate gradient)的实现与torch自带的有些许不一样,于是打算查下资料了解清楚。

      先回忆下Momentm,该梯度下降法引入动量的概念,使用β对历史梯度进行滑动指数加权平均,最早的梯度衰减的最快,对当前更新影响小;反之,越接近当前的梯度对更新的影响越大,公式为:
      ~A1E~JC(`1PVA}6A{VX~1TO.png
      其中Vt、gt、g(θt)分别代表t时刻的速度、梯度、模型参数,μ是动量系数,lr是学习率。该方法的思想是对网络参数进行平滑处理,让梯度的摆动幅度不要太大。

      NAG类似Momentum,它们都是利用历史梯度来更新参数,区别在于,NAG先利用μVt,对θt进行部分更新得到θt+μVt,然后利用梯度g(θt+μVt)更新得到θt+1,其公式如下所示:
      0b548033-acf7-443c-a3e1-63dad71b448a-image.png
      此处ε是学习率。
      下图对Momentum和NAG作了形象解释:
      2f7cf5bf-0cd2-4372-be18-40232b3b8d45-image.png
      Momentum使用当前位置A处的速度Vt和梯度g(θt)直接更新到目的地C;而NAG从A点先沿着惯性方向走一小步到B,此处距C很接近了, 再利用B处的梯度g(θt+μVt)更新到C。

      论文中认为这样可以快速更新V,使得Nag比momentum更稳定,且更适合于大学习率的场景。除此之外,如果Nag用μVt更新到B点较差时,由于B点梯度g(θt+μVt)比momentum的g(θt)更大,因此Nag能更快往回修正到起始点A。

      言归正传,这是torch.optim.SGD的公式和代码[1]:
      bdefa8bc-17ff-49d9-be5a-36d033e48cae-image.png
      42f9a14a-577f-46d5-bf01-f3d23ef7036b-image.png

      这是fairseq.optim.nag的公式和代码[2]:
      ca9833e5-5ed5-40f2-bb69-b42ebd434cf7-image.png
      df40b1ba-49e1-47a5-a8e3-897d64af1854-image.png
      可以看出两者实际上还是有些不同,而Fairseq的nag实际上和论文的公式基本一致,[3]中有推导:
      11dce8f3-c11a-4070-9936-1e25351d8ab5-image.png
      其中的β就是本文的动量系数μ,先对θt+βVt做了代换得到θt’后,最后将θt’当成待更新的参数θt,也就是每次更新的始终是θt+βVt,关于这个的解释见下图及[4]:
      f74fee8c-81c6-4dcf-9963-d0b8695ee67d-image.png

      总之,nag优化器能加速收敛,且使用很大的学习率也很稳定,难怪fairseq里面ConvS2S能使用0.5的学习率。

      [1]torch sgd
      [2]fairseq nag
      [3]深度学习中优化方法
      [4]CS231n Convolutional Neural Networks for Visual Recognition

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • [机器翻译] 21.7 mRASP2

      Contrastive Learning for Many-to-many Multilingual Neural Machine Translation
      github:

      摘要:

      现有的多语言模型聚焦于英语为中心的翻译,而非英语的方向远远落后。本文旨在一个多对多翻译系统,重点是非英语语言方向的质量。基于这样一个假设:通用的跨语言表示会导致更好的多语言翻译性能。为此提出了一种训练方法mRASP2,以获得单一统一的多语言翻译模型。mRASP2的核心在于如下两点:

      1. 通过对比学习拉近多语言表示对齐语义空间
      2. 同时使用平行和单语语料进行对齐增强

      结论:

      1. 对比学习确实能提升零资源翻译
      2. 使用单语数据,所有翻译方向上都取得了实质性的改进。
      3. 分析并可视化了本文方法,对比学习确实能够拉近不同语言语义的表征
      4. 未来打算使用更大数据集训练模型PC150

      方法:

      1.损失函数

      损失为交叉熵Lce和对比损失Lctr的加权和,|s|是平均句子长度,因为Lce是词级别的,而Lctr是序列级别的,两者有比例关系,因此要乘上平均句子长度。

      a2d8700b-7206-4977-91f6-c57372d76ad8-image.png
      xi,xj是平行语料。Lce计算常规decoder输出和label的交叉熵,旨在让解码器输出分布与真实分布一致。
      76cdb4ae-2613-4352-bda6-1376e9f2e31f-image.png
      而对比损失Lctr为了拉近语义空间中跨语言同义词的表征距离,并且拉远非同义词表征的距离。具体为:以某个样本点的源端向量表示为锚点,以该样本目标端的向量表征为正样本(过encoder),以同一个batch中其他样本点的目标端句子向量表示为负样本,最小化锚点和正样本的距离,最大化锚点和所以负样本的距离。
      f86c2f6d-9193-4f76-99fb-b43c8e4be414-image.png
      3e554e43-071a-47bc-913d-badf52716816-image.png
      其中距离使用的是余弦距离,分子是锚点和正例的距离,分母是所有负例和锚点的距离和,通过最小化Lctr就能达到拉近同义词表征、拉远非同义词表征的目的。

      引入对比学习,可以在不降低其他翻译方向的基础上,提高零资源翻译的性能。

      2.对齐增强

      b7f60901-713d-41d6-9743-a0e50cba1b23-image.png
      其中距离使用的是余弦距离,分子是锚点和正例的距离,分母是所有负例和锚点的距离和,通过最小化Lctr就能达到拉近同义词表征、拉远非同义词表征的目的。

      实验结果

      相比多语言基线模型m-Transformer,mRASP2在表中的10个方向上都有显著的提升。

      c14281db-4865-48c7-a4fc-66f7c84584e5-image.png
      在无监督翻译(至少一端的语料在预训练时出现过)上平均超过了基线十多点。
      b78da7d7-a98a-4690-89c6-aba3182157f4-image.png
      217ae51b-2072-4bbb-9993-445fe6716c53-image.png
      即使是在零资源翻译(非英语对翻译)上性能也很卓越,和桥接模型差不多(pivot)。
      14767123-15e4-477a-93e7-00d71dfbeb08-image.png

      可视化分析

      dd1b8ef1-6736-44f4-a529-80d67b4bea61-image.png
      使用T-SNE对英、日、德三种语言同义句的语义空间表征降维后可视化,发现使用mRASP(b)比基线transformer更好的拉近了多语言同义句的语义表征。

      个人总结

      对比学习yyds,接下来准备找代码试试。

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • [文本分类] 文本数据增强1

      最近在做新闻标题分类,找了篇数据增强的文章学习学习:
      一篇就够!数据增强方法综述
      本文实现了EDA(简单数据增强)和回译:

      一. EDA

      1.1 随机替换

      04875152-8acd-4a20-82a2-c594cf6b70a9-image.png

      import random
      import jieba
      import numpy as np
      import paddle
      from paddlenlp.embeddings import TokenEmbedding
      # 从词向量中按余弦相似度找与某个词的topk近义词
      def get_similar_tokens_raw(query_token, k, token_embedding):
          W = np.asarray(token_embedding.weight.numpy())
          x = np.asarray(token_embedding.search(query_token).reshape(-1))
          cos = np.dot(W, x) / np.sqrt(np.sum(W * W, axis=1) * np.sum(x * x) + 1e-9)
          flat = cos.flatten()
          # argpartition在k个位置放第k大的索引,左边比他小,右边比他大,复杂度仅o(n)
          # 取-k则在-k和他右边的为topk,对他们再排次序就好了
          indices = np.argpartition(flat, -k)[-k:] 
          indices = indices[np.argsort(-flat[indices])] # 取负从大到小排
          return token_embedding.vocab.to_tokens(indices)
      # 随机替换
      def random_replace(words,token_embedding,prob=0.1,max_change=3):
          change_num=0
          for idx in range(len(words)):
              prob_i=prob*(len(words[idx])-0.5) # -0.5使得长度1的词概率乘2,不易选中
              if random.uniform(0,1)<prob_i: # 词越长,越容易被替换
                  sim_words=get_similar_tokens_raw(words[idx],k=5,token_embedding=token_embedding)
                  words[idx]=random.choice(sim_words)
                  change_num+=1
              if change_num>=max_change:
                  break
          return words
      

      由于get_similar_tokens_raw一次只能取一个词的近义词较慢,于是改成了一次取多个词的近义词,效果如下:
      bcfd42a9-38e1-44b1-bcaf-d45103ce2681-image.png

      # 查询多个词的topk近义词
      def get_similar_tokens_multi(query_tokens, k, token_embedding):
          n_tokens=len(query_tokens)
          W = paddle.to_tensor(token_embedding.weight.detach(),dtype='float16')
          q_idx=token_embedding.search(query_tokens)
          x = paddle.to_tensor(q_idx,dtype='float16').transpose((1,0))
          cos = paddle.matmul(W, x) / paddle.sqrt(paddle.sum(W * W, axis=1,keepdim=True) * paddle.sum(x * x,keepdim=True) + 1e-9)
      
          def sort_row_by_idx(input, indices):
              assert input.shape == indices.shape
              row, col = input.shape
              indices = indices * col + np.arange(0, col)
              indices = indices.reshape(-1)
              input = input.reshape(-1)[indices].reshape(row, -1)
              return input
      
          part_indices = np.argpartition(cos.numpy(), -k, axis=0)
          out = sort_row_by_idx(cos.numpy(), part_indices)[-k:, :]
          new_idx = np.argsort(-out, axis=0)
          # 用新的索引对旧的part的索引排序
          indices = sort_row_by_idx(part_indices[-k:, :], new_idx).reshape(-1)
          sim_tokens=token_embedding.vocab.to_tokens(indices)
          sim_tokens=np.array(sim_tokens).reshape(k,n_tokens)
          if k>=2:sim_tokens=sim_tokens[:-1,:]
          return sim_tokens.transpose()
      # 相应的随机替换(此函数会多返回个近义词列表,供随机插入使用)
      def random_replace(words,token_embedding,prob=0.1,max_change=3):
          words=np.array(words)
          probs=np.random.uniform(0,1,(len(words),))
          words_len=np.array([len(word) for word in words])-0.5 # 惩罚1的
          probs=probs/words_len
          mask=probs<prob
          if sum(mask)>1:
              replace_words=words[mask].tolist()
              sim_words=get_similar_tokens_multi(query_tokens=replace_words,k=5,token_embedding=token_embedding)
              choosed=[]
              for row in sim_words:
                  choosed.append(np.random.choice(row))
              words[mask]=np.array(choosed)
              return words.tolist(),sim_words.flatten().tolist()
          return words.tolist(),[]
      
      if __name__ == '__main__':
          token_embedding=TokenEmbedding(embedding_name="w2v.baidu_encyclopedia.target.word-word.dim300")
          # 近义词查找
          words=['苹果','美国','国王','总统','台风','雷电','奥特曼']
          sim_words=get_similar_tokens_multi(query_tokens=words,k=5,token_embedding=token_embedding)
          print('raw words:',words)
          print('sim_words:',sim_words)
      

      1.2 随机插入

      随机在语句中插入n个词 (从随机替换返回的近义词列表sim_words采样,如果sim_words=None,则从原句中随机采样)
      293e5ad4-9b6b-44d3-9151-93ff34610c42-image.png

      def random_insertion(words,sim_words=None,n=3):
          new_words = words.copy()
          for _ in range(n):
              add_word(new_words,sim_words)
          return new_words
      
      def add_word(new_words,sim_words=None):
          random_synonym = random.choice(sim_words) if sim_words else random.choice(new_words)
          random_idx = random.randint(0, len(new_words) - 1)
          new_words.insert(random_idx, random_synonym)  # 随机插入
      

      1.3 随机删除

      对句子中每个词依概率p随机删除,此处按词长度加权,越长越不易被删除,代码如下:
      bc33a893-70ce-4cd1-80c5-ac2023aaaa93-image.png
      f516294e-7600-4a97-af43-e7a96eef3bd7-image.png

      def random_deletion(words,prob=0.1):
          probs=np.random.uniform(0,1,(len(words),))
          words_len=np.array([len(word) for word in words])
          # 对长词加大权重,防止被删除重要词
          probs=probs*words_len
          mask=probs>prob
          return np.array(words)[mask].tolist()
      

      1.4 随机置换临近词

      人在读阅句子时,往往乱打顺序也能理句解意,不信您回过去再读一遍哈哈,代码如下:
      9c51f523-d2b2-43e5-a832-e0f678cd99c4-image.png

      # 先获取词索引,再对某个词添加个噪声noise∈[0,n],n(window_size)一般取3,然后
      # 重新排序后就能达到目的了
      def random_permute(words,window_size):
          noise=np.random.uniform(0,window_size,size=(len(words),))
          idx=np.arange(0,len(words))
          new_idx=np.argsort(noise+idx)
          return np.array(words)[new_idx].tolist()
      

      二. 回译

      回译是机器翻译里常用的对单语语料进行增强方法:对目标端单语语料t,利用反向翻译模型(tgt2src)生成源端的伪数据s’,从而让正向的src2tgt翻译模型使用伪平行语料(s’,t)继续训练。
      本文使用预训练的mbart50(50种语言)进行回译,可以对原始语料zh,进行如下方向翻译:
      中->法->xxxx->英->中,简单起见本文就进行中英中回译:

      回译示例:
      1e663869-fdf1-4e32-ae04-f0e06ada9666-image.png

      import torch
      from transformers import MBartForConditionalGeneration,MBart50TokenizerFast
      device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
      model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
      tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
      model.eval()
      
      batch_sentences=['网易第三季度业绩低于分析师预期',
                       '巴萨1年前地狱重现这次却是天堂 再赴魔鬼客场必翻盘',
                       '美国称支持向朝鲜提供紧急人道主义援助',
                       '蔡少芬要补交税款几十万 圣诞节拼命赚外快(图)']
      print('input:','\n'.join(batch_sentences))
      # 中->英
      tokenizer.src_lang='zh_CN' # 设置输入为中文
      batch_tokenized = tokenizer.batch_encode_plus(batch_sentences, add_special_tokens=True,padding=True, pad_to_max_length=True)
      input_dict = {'input_ids':torch.LongTensor(batch_tokenized['input_ids']).to(device),
                    "attention_mask":torch.LongTensor(batch_tokenized['attention_mask']).to(device)}
      
      batch_tokens=model.generate(**input_dict,forced_bos_token_id=tokenizer.lang_code_to_id['en_XX']) # 输出为英文
      en_sent=tokenizer.batch_decode(batch_tokens, skip_special_tokens=True)
      print('en:','\n'.join(en_sent))
      
      # 英->中
      tokenizer.src_lang='en_XX' # 设置输入为英文
      batch_tokenized = tokenizer.batch_encode_plus(en_sent, add_special_tokens=True,padding=True, pad_to_max_length=True)
      input_dict = {'input_ids':torch.LongTensor(batch_tokenized['input_ids']).to(device),
                    "attention_mask":torch.LongTensor(batch_tokenized['attention_mask']).to(device)}
      
      batch_tokens=model.generate(**input_dict,forced_bos_token_id=tokenizer.lang_code_to_id['zh_CN']) # 输出为中文
      zh_sent=tokenizer.batch_decode(batch_tokens, skip_special_tokens=True)
      print('zh:','\n'.join(zh_sent))
      '''
      mbart50覆盖如下语言:
      Arabic (ar_AR), Czech (cs_CZ), German (de_DE), English (en_XX), Spanish (es_XX), Estonian (et_EE), Finnish (fi_FI), French (fr_XX), Gujarati (gu_IN), Hindi (hi_IN), Italian (it_IT), Japanese (ja_XX), Kazakh (kk_KZ), Korean (ko_KR), Lithuanian (lt_LT), Latvian (lv_LV), Burmese (my_MM), Nepali (ne_NP), Dutch (nl_XX), Romanian (ro_RO), Russian (ru_RU), Sinhala (si_LK), Turkish (tr_TR), Vietnamese (vi_VN), Chinese (zh_CN), Afrikaans (af_ZA), Azerbaijani (az_AZ), Bengali (bn_IN), Persian (fa_IR), Hebrew (he_IL), Croatian (hr_HR), Indonesian (id_ID), Georgian (ka_GE), Khmer (km_KH), Macedonian (mk_MK), Malayalam (ml_IN), Mongolian (mn_MN), Marathi (mr_IN), Polish (pl_PL), Pashto (ps_AF), Portuguese (pt_XX), Swedish (sv_SE), Swahili (sw_KE), Tamil (ta_IN), Telugu (te_IN), Thai (th_TH), Tagalog (tl_XX), Ukrainian (uk_UA), Urdu (ur_PK), Xhosa (xh_ZA), Galician (gl_ES), Slovene (sl_SI
      '''
      
      
      # 离线回译增强,将文本文件按行回译,
      import torch
      from functools import partial
      from transformers import MBartForConditionalGeneration,MBart50TokenizerFast
      from tqdm import tqdm
      
      def get_data_iterator(input_path):
          with open(input_path, 'r', encoding="utf-8") as f:
              for line in f.readlines():
                  line=line.strip()
                  yield line
      
      # 迭代器: 生成一个batch的数据
      def get_batch_iterator(data_path, batch_size=32,drop_last=False):
          keras_bert_iter = get_data_iterator(data_path)
          continue_iterator = True
          while True:
              batch_data = []
              for _ in range(batch_size):
                  try:
                      data = next(keras_bert_iter)
                      batch_data.append(data)
                  except StopIteration:
                      continue_iterator = False
                      break
      
              if continue_iterator:# 刚好一个batch
                  yield batch_data
              else: # 不足一batch
                  if not drop_last:
                      yield batch_data
                  return StopIteration
      
      @torch.no_grad()
      def batch_translation(batch_sentences,model,tokenizer,src_lang,tgt_lang,max_len=128):
          device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
          model.to(device)
          model.eval()
          tokenizer.src_lang=src_lang
          # token2id
          encoded_inputs=tokenizer.batch_encode_plus(batch_sentences, add_special_tokens=True,
                                                       padding=True, pad_to_max_length=True)
      #                                 max_length=max_len, pad_to_max_length=True)
          # list->tensor
          encoded_inputs['input_ids']=torch.LongTensor(encoded_inputs['input_ids']).to(device)
          encoded_inputs['attention_mask']=torch.LongTensor(encoded_inputs['attention_mask']).to(device)
          # generate
          batch_tokens = model.generate(**encoded_inputs, forced_bos_token_id=tokenizer.lang_code_to_id[tgt_lang])
          # decode
          tgt_sentences = tokenizer.batch_decode(batch_tokens, skip_special_tokens=True)
          return tgt_sentences
      
      def translate_file(src_path,tgt_path,src_lang,tgt_lang,batch_size=32,max_len=128):
          # data
          batch_iter=get_batch_iterator(src_path,batch_size=batch_size)
          # model
          model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
          tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
          src2tgt_fn = partial(batch_translation, model=model, tokenizer=tokenizer,
                               src_lang=src_lang, tgt_lang=tgt_lang,max_len=None)
          result=[]
          i=0
          for batch_sentences in tqdm(batch_iter):
              tgt_sentences = src2tgt_fn(batch_sentences)
              result.extend(tgt_sentences)
              if i%100==0:
                  print(f'src:{batch_sentences[0]}==>tgt:{tgt_sentences[0]}')
              i+=1
      
          # write 2 file
          with open(tgt_path,'w',encoding='utf-8') as f:
              f.write('\n'.join(result))
              print(f'write 2 {tgt_path} success.')
      
      if __name__ == '__main__':
          src_path='train.txt'
          mid_path='train.en'
          tgt_path='train_back.txt'
          # translate zh to en
          translate_file(src_path, mid_path, src_lang='zh_CN', tgt_lang='en_XX', batch_size=16)
          # translate en to zh
          translate_file(mid_path, tgt_path, src_lang='en_XX', tgt_lang='zh_CN', batch_size=16)
      

      总结:

      数据增强作用有限,接下来准备在相关任务数据上继续预训练。

      参考:

      1.一篇就够!数据增强方法综述
      2.回译
      3.mbart50
      4.机器翻译:基础和模型

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • [机器翻译] 21.1 字节跳动的mRASP预训练模型

      1.引言

      最近在看机器翻译文献时,常常望卡兴叹,尤其是facebook是真的壕,训练25种语言的mBart就用256张卡训练了20天,更不用说是mBart50。偶然发现这篇字节的mRASP( Random Aligned Substitution Pre-training )模型号称只需要8卡一周,简直太香了!(还是跑不起啊orz)论文为:Pre-training Multilingual Neural Machine Translation by Leveraging Alignment Information,内容如下:

      2.摘要:

      本文想构建一个统一的机器翻译模型,在提供任意语言对的情况下,可以快速适应新语言。于是提出一种通用的多语言机器翻译预训练模型:mRASP(多语言随机对齐预训练),在32种语言上进行预训练(双语数据),然后在42个翻译方向上进行微调,结果证明在低、中、高乃至零资源翻译上都有非常大的提升。本文首次验证多语言模型能提升富资源语言的效果。

      3.结论:

      mRASP可以使跨语言的同义词在嵌入空间上接近,在低、中、高和零资源数据上证明了模型效性。通过分析实验,发现对齐信息确实能不同语言语义上的鸿沟,并提升性能。
      未来工作是探索更多词对齐的方法,并在大规模数据上预训练进一步提升性能。

      4.介绍:

      1.本文认为预训练模型在nmt任务上的限制在于:
      (1)预训练的bert不能直接微调到nmt,除非用些复杂的办法。
      (2)预训练目标和下游任务(nmt)的训练目标有差异:如mass、mbart使用自编码器(降噪),和翻译任务不同,因此微调之后收益有限。
      (3)现有的多语言预训练方法仅能提升中、低资源翻译,而非任意语料对,尤其是对富资源上效果没有显著提升。(想想看人类学会多种语言后再学其他语言应该会很快)
      2.本文使用随机对齐替换使模型能弥合跨语言的鸿沟(见下),充分利用多语言知识,使得相同语义的语言在表征空间接近。mRASP在极端缺少平行语料(<10w),能达到22bleu。
      3.提出了异国翻译的四种分类法:
      (1)Exotic Pair:微调时的源语言和目标语言在预训练时各自单独出现过,但是没有成对训练;
      (2)Exotic Source:微调时的源语言没有在预训练时出现,只预训练过目标语言;
      (3)Exotic Target:微调时的目标语言没有在预训练时出现,只预训练过源语言;
      (4)Exotic Full:微调的两端语言在预训练中都没出现过(巨难);
      4.贡献
      (1)使用上亿对双语语料进行预训练,而不像其他模型一样用大量单语预训练。本文认为预训练和微调有一致的目标有利于nmt提升;
      (2)提出RAS,能够弥合跨语言的语义空间;
      (3)在42个方向上取得巨大提升,在预训练中源、目标语言都没有的极端情况(Exotic Full)取得14的bleu,在富语言en-fr上能进一步取得提升44.3bleu。

      5.模型:

      5.1.结构

      采用transformer-large,编码器解码器各6层,嵌入维度1024,14个head,激活函数换为GeLU,并使用可学习的位置嵌入。

      5.2.随机对齐替换

      不多说,先上图:
      b1d06413-2d77-4f37-a8f3-c406d2f3364f-image.png
      源句是:“ I like singing and dancing”,目标句是:“J’adore chanter et danser <EOS>”
      随机对齐替换就是无监督MUSE方法构建词典,然后随机替换掉源句种的“singing ”和“dancing”,编码器输入变为:“I like chanter and danser”,解码器的生成目标不变。
      我们知道一个词的词义是由其上下文决定的,因此把“chanter ”放到和“singing”同样的语境下,他们在嵌入空间的距离就拉近了,从而达到跨语言语义相近的目的。
      换成公式就是如下:
      8d978d61-0565-4592-b493-281e17cda3d7-image.png
      L={L1,…Lm}为预训练的语言集合,xi代表语言Li中的某个句子。Dij是平行语料,N是平行语料数。C是对齐函数,用于把源句中的单词替换为随机语言对应的词。在翻译方向为(xj,xi)时,目标函数使源语句xj在经随机替换后C(xj)条件下,得到翻译结果xi的概率最大,即最小化化负对数似然。

      5.3.语言标识

      为区分不同翻译对,在源和目标语句之前简单添加语言标识:
      460ca861-f2de-4cd7-ab57-2ccf785d5373-image.png

      5.4.灵感来源:

      最近的工作证明,跨语言模型预训练可能是一种更有效的方法来进行表征学习。然而
      在预训练时,跨语言信息是从共享子词表获得的,有如下局限:
      (1)共享词汇表非常系数,尤其是在不同的语言对上(形态上完全不一样,如英汉)
      (2)即使是相同的子词,在不同语言中也可能表示不同意思。
      (3)参数共享的方法缺乏明确的监督信号,来引导跨语言中相同意思词共享相同的语义空间
      因此本文为了弥合跨语言语义的鸿沟,提出了RAS随机对齐替换的方法。

      5.5 PC32(Parallel Corpus 32)

      收集了32个英文为中心的语言,64个翻译方向,统称为PC32,共包含197m平行语料

      792028c4-35ac-4911-9019-382eb1afe564-image.png

      5.6 预训练细节

      词汇表:
      使用联合词汇表,用共享bpe,32k次合并操作。数据使用全部平行语料和额外的1m单语数据。并且为了平衡不同语言的词汇表大小,在最大语料量语言的基础上,对其他低资源语言进行过采样,使得每个token出现数超过20,最终子词词汇表大小是64808。
      参数
      Adam优化器,eps= 1e − 8, β2 = 0.98,warmup=4000步,预训练15w次。
      RAS使用MUSE得到的English-X词典,取前1000个,用来随机替换源端的词,每个词有30%概率被替换。为解决一词多义,从候选词中随机选一个用来替换。
      结果:

      6. 微调结果

      在富资源语言上效果明显:
      4e54d55e-070d-49c7-8866-305f1f5f11b2-image.png
      在零资源语言上吊打直接训练。
      214ed334-b691-4813-8585-4be03fa5e532-image.png

      7.个人总结

      mRASP构建了一种通用机器翻译模型,能快速适应各种语言,且训练速度快,可以看出多语言机器翻译是大势所趋。不过本文使用的也是共享词汇表,在跨语系如中英时词汇表会很大很稀疏,使用类似通用词表嵌入的方法或许能在对不同语言词表解耦的同时,进一步拉近语义空间。

      posted in 语音识别与语义处理领域
      173****5160
      173****5160

    Latest posts made by 173****5160

    • [文本分类] 文本数据增强1

      最近在做新闻标题分类,找了篇数据增强的文章学习学习:
      一篇就够!数据增强方法综述
      本文实现了EDA(简单数据增强)和回译:

      一. EDA

      1.1 随机替换

      04875152-8acd-4a20-82a2-c594cf6b70a9-image.png

      import random
      import jieba
      import numpy as np
      import paddle
      from paddlenlp.embeddings import TokenEmbedding
      # 从词向量中按余弦相似度找与某个词的topk近义词
      def get_similar_tokens_raw(query_token, k, token_embedding):
          W = np.asarray(token_embedding.weight.numpy())
          x = np.asarray(token_embedding.search(query_token).reshape(-1))
          cos = np.dot(W, x) / np.sqrt(np.sum(W * W, axis=1) * np.sum(x * x) + 1e-9)
          flat = cos.flatten()
          # argpartition在k个位置放第k大的索引,左边比他小,右边比他大,复杂度仅o(n)
          # 取-k则在-k和他右边的为topk,对他们再排次序就好了
          indices = np.argpartition(flat, -k)[-k:] 
          indices = indices[np.argsort(-flat[indices])] # 取负从大到小排
          return token_embedding.vocab.to_tokens(indices)
      # 随机替换
      def random_replace(words,token_embedding,prob=0.1,max_change=3):
          change_num=0
          for idx in range(len(words)):
              prob_i=prob*(len(words[idx])-0.5) # -0.5使得长度1的词概率乘2,不易选中
              if random.uniform(0,1)<prob_i: # 词越长,越容易被替换
                  sim_words=get_similar_tokens_raw(words[idx],k=5,token_embedding=token_embedding)
                  words[idx]=random.choice(sim_words)
                  change_num+=1
              if change_num>=max_change:
                  break
          return words
      

      由于get_similar_tokens_raw一次只能取一个词的近义词较慢,于是改成了一次取多个词的近义词,效果如下:
      bcfd42a9-38e1-44b1-bcaf-d45103ce2681-image.png

      # 查询多个词的topk近义词
      def get_similar_tokens_multi(query_tokens, k, token_embedding):
          n_tokens=len(query_tokens)
          W = paddle.to_tensor(token_embedding.weight.detach(),dtype='float16')
          q_idx=token_embedding.search(query_tokens)
          x = paddle.to_tensor(q_idx,dtype='float16').transpose((1,0))
          cos = paddle.matmul(W, x) / paddle.sqrt(paddle.sum(W * W, axis=1,keepdim=True) * paddle.sum(x * x,keepdim=True) + 1e-9)
      
          def sort_row_by_idx(input, indices):
              assert input.shape == indices.shape
              row, col = input.shape
              indices = indices * col + np.arange(0, col)
              indices = indices.reshape(-1)
              input = input.reshape(-1)[indices].reshape(row, -1)
              return input
      
          part_indices = np.argpartition(cos.numpy(), -k, axis=0)
          out = sort_row_by_idx(cos.numpy(), part_indices)[-k:, :]
          new_idx = np.argsort(-out, axis=0)
          # 用新的索引对旧的part的索引排序
          indices = sort_row_by_idx(part_indices[-k:, :], new_idx).reshape(-1)
          sim_tokens=token_embedding.vocab.to_tokens(indices)
          sim_tokens=np.array(sim_tokens).reshape(k,n_tokens)
          if k>=2:sim_tokens=sim_tokens[:-1,:]
          return sim_tokens.transpose()
      # 相应的随机替换(此函数会多返回个近义词列表,供随机插入使用)
      def random_replace(words,token_embedding,prob=0.1,max_change=3):
          words=np.array(words)
          probs=np.random.uniform(0,1,(len(words),))
          words_len=np.array([len(word) for word in words])-0.5 # 惩罚1的
          probs=probs/words_len
          mask=probs<prob
          if sum(mask)>1:
              replace_words=words[mask].tolist()
              sim_words=get_similar_tokens_multi(query_tokens=replace_words,k=5,token_embedding=token_embedding)
              choosed=[]
              for row in sim_words:
                  choosed.append(np.random.choice(row))
              words[mask]=np.array(choosed)
              return words.tolist(),sim_words.flatten().tolist()
          return words.tolist(),[]
      
      if __name__ == '__main__':
          token_embedding=TokenEmbedding(embedding_name="w2v.baidu_encyclopedia.target.word-word.dim300")
          # 近义词查找
          words=['苹果','美国','国王','总统','台风','雷电','奥特曼']
          sim_words=get_similar_tokens_multi(query_tokens=words,k=5,token_embedding=token_embedding)
          print('raw words:',words)
          print('sim_words:',sim_words)
      

      1.2 随机插入

      随机在语句中插入n个词 (从随机替换返回的近义词列表sim_words采样,如果sim_words=None,则从原句中随机采样)
      293e5ad4-9b6b-44d3-9151-93ff34610c42-image.png

      def random_insertion(words,sim_words=None,n=3):
          new_words = words.copy()
          for _ in range(n):
              add_word(new_words,sim_words)
          return new_words
      
      def add_word(new_words,sim_words=None):
          random_synonym = random.choice(sim_words) if sim_words else random.choice(new_words)
          random_idx = random.randint(0, len(new_words) - 1)
          new_words.insert(random_idx, random_synonym)  # 随机插入
      

      1.3 随机删除

      对句子中每个词依概率p随机删除,此处按词长度加权,越长越不易被删除,代码如下:
      bc33a893-70ce-4cd1-80c5-ac2023aaaa93-image.png
      f516294e-7600-4a97-af43-e7a96eef3bd7-image.png

      def random_deletion(words,prob=0.1):
          probs=np.random.uniform(0,1,(len(words),))
          words_len=np.array([len(word) for word in words])
          # 对长词加大权重,防止被删除重要词
          probs=probs*words_len
          mask=probs>prob
          return np.array(words)[mask].tolist()
      

      1.4 随机置换临近词

      人在读阅句子时,往往乱打顺序也能理句解意,不信您回过去再读一遍哈哈,代码如下:
      9c51f523-d2b2-43e5-a832-e0f678cd99c4-image.png

      # 先获取词索引,再对某个词添加个噪声noise∈[0,n],n(window_size)一般取3,然后
      # 重新排序后就能达到目的了
      def random_permute(words,window_size):
          noise=np.random.uniform(0,window_size,size=(len(words),))
          idx=np.arange(0,len(words))
          new_idx=np.argsort(noise+idx)
          return np.array(words)[new_idx].tolist()
      

      二. 回译

      回译是机器翻译里常用的对单语语料进行增强方法:对目标端单语语料t,利用反向翻译模型(tgt2src)生成源端的伪数据s’,从而让正向的src2tgt翻译模型使用伪平行语料(s’,t)继续训练。
      本文使用预训练的mbart50(50种语言)进行回译,可以对原始语料zh,进行如下方向翻译:
      中->法->xxxx->英->中,简单起见本文就进行中英中回译:

      回译示例:
      1e663869-fdf1-4e32-ae04-f0e06ada9666-image.png

      import torch
      from transformers import MBartForConditionalGeneration,MBart50TokenizerFast
      device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
      model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
      tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
      model.eval()
      
      batch_sentences=['网易第三季度业绩低于分析师预期',
                       '巴萨1年前地狱重现这次却是天堂 再赴魔鬼客场必翻盘',
                       '美国称支持向朝鲜提供紧急人道主义援助',
                       '蔡少芬要补交税款几十万 圣诞节拼命赚外快(图)']
      print('input:','\n'.join(batch_sentences))
      # 中->英
      tokenizer.src_lang='zh_CN' # 设置输入为中文
      batch_tokenized = tokenizer.batch_encode_plus(batch_sentences, add_special_tokens=True,padding=True, pad_to_max_length=True)
      input_dict = {'input_ids':torch.LongTensor(batch_tokenized['input_ids']).to(device),
                    "attention_mask":torch.LongTensor(batch_tokenized['attention_mask']).to(device)}
      
      batch_tokens=model.generate(**input_dict,forced_bos_token_id=tokenizer.lang_code_to_id['en_XX']) # 输出为英文
      en_sent=tokenizer.batch_decode(batch_tokens, skip_special_tokens=True)
      print('en:','\n'.join(en_sent))
      
      # 英->中
      tokenizer.src_lang='en_XX' # 设置输入为英文
      batch_tokenized = tokenizer.batch_encode_plus(en_sent, add_special_tokens=True,padding=True, pad_to_max_length=True)
      input_dict = {'input_ids':torch.LongTensor(batch_tokenized['input_ids']).to(device),
                    "attention_mask":torch.LongTensor(batch_tokenized['attention_mask']).to(device)}
      
      batch_tokens=model.generate(**input_dict,forced_bos_token_id=tokenizer.lang_code_to_id['zh_CN']) # 输出为中文
      zh_sent=tokenizer.batch_decode(batch_tokens, skip_special_tokens=True)
      print('zh:','\n'.join(zh_sent))
      '''
      mbart50覆盖如下语言:
      Arabic (ar_AR), Czech (cs_CZ), German (de_DE), English (en_XX), Spanish (es_XX), Estonian (et_EE), Finnish (fi_FI), French (fr_XX), Gujarati (gu_IN), Hindi (hi_IN), Italian (it_IT), Japanese (ja_XX), Kazakh (kk_KZ), Korean (ko_KR), Lithuanian (lt_LT), Latvian (lv_LV), Burmese (my_MM), Nepali (ne_NP), Dutch (nl_XX), Romanian (ro_RO), Russian (ru_RU), Sinhala (si_LK), Turkish (tr_TR), Vietnamese (vi_VN), Chinese (zh_CN), Afrikaans (af_ZA), Azerbaijani (az_AZ), Bengali (bn_IN), Persian (fa_IR), Hebrew (he_IL), Croatian (hr_HR), Indonesian (id_ID), Georgian (ka_GE), Khmer (km_KH), Macedonian (mk_MK), Malayalam (ml_IN), Mongolian (mn_MN), Marathi (mr_IN), Polish (pl_PL), Pashto (ps_AF), Portuguese (pt_XX), Swedish (sv_SE), Swahili (sw_KE), Tamil (ta_IN), Telugu (te_IN), Thai (th_TH), Tagalog (tl_XX), Ukrainian (uk_UA), Urdu (ur_PK), Xhosa (xh_ZA), Galician (gl_ES), Slovene (sl_SI
      '''
      
      
      # 离线回译增强,将文本文件按行回译,
      import torch
      from functools import partial
      from transformers import MBartForConditionalGeneration,MBart50TokenizerFast
      from tqdm import tqdm
      
      def get_data_iterator(input_path):
          with open(input_path, 'r', encoding="utf-8") as f:
              for line in f.readlines():
                  line=line.strip()
                  yield line
      
      # 迭代器: 生成一个batch的数据
      def get_batch_iterator(data_path, batch_size=32,drop_last=False):
          keras_bert_iter = get_data_iterator(data_path)
          continue_iterator = True
          while True:
              batch_data = []
              for _ in range(batch_size):
                  try:
                      data = next(keras_bert_iter)
                      batch_data.append(data)
                  except StopIteration:
                      continue_iterator = False
                      break
      
              if continue_iterator:# 刚好一个batch
                  yield batch_data
              else: # 不足一batch
                  if not drop_last:
                      yield batch_data
                  return StopIteration
      
      @torch.no_grad()
      def batch_translation(batch_sentences,model,tokenizer,src_lang,tgt_lang,max_len=128):
          device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
          model.to(device)
          model.eval()
          tokenizer.src_lang=src_lang
          # token2id
          encoded_inputs=tokenizer.batch_encode_plus(batch_sentences, add_special_tokens=True,
                                                       padding=True, pad_to_max_length=True)
      #                                 max_length=max_len, pad_to_max_length=True)
          # list->tensor
          encoded_inputs['input_ids']=torch.LongTensor(encoded_inputs['input_ids']).to(device)
          encoded_inputs['attention_mask']=torch.LongTensor(encoded_inputs['attention_mask']).to(device)
          # generate
          batch_tokens = model.generate(**encoded_inputs, forced_bos_token_id=tokenizer.lang_code_to_id[tgt_lang])
          # decode
          tgt_sentences = tokenizer.batch_decode(batch_tokens, skip_special_tokens=True)
          return tgt_sentences
      
      def translate_file(src_path,tgt_path,src_lang,tgt_lang,batch_size=32,max_len=128):
          # data
          batch_iter=get_batch_iterator(src_path,batch_size=batch_size)
          # model
          model = MBartForConditionalGeneration.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
          tokenizer = MBart50TokenizerFast.from_pretrained("facebook/mbart-large-50-many-to-many-mmt")
          src2tgt_fn = partial(batch_translation, model=model, tokenizer=tokenizer,
                               src_lang=src_lang, tgt_lang=tgt_lang,max_len=None)
          result=[]
          i=0
          for batch_sentences in tqdm(batch_iter):
              tgt_sentences = src2tgt_fn(batch_sentences)
              result.extend(tgt_sentences)
              if i%100==0:
                  print(f'src:{batch_sentences[0]}==>tgt:{tgt_sentences[0]}')
              i+=1
      
          # write 2 file
          with open(tgt_path,'w',encoding='utf-8') as f:
              f.write('\n'.join(result))
              print(f'write 2 {tgt_path} success.')
      
      if __name__ == '__main__':
          src_path='train.txt'
          mid_path='train.en'
          tgt_path='train_back.txt'
          # translate zh to en
          translate_file(src_path, mid_path, src_lang='zh_CN', tgt_lang='en_XX', batch_size=16)
          # translate en to zh
          translate_file(mid_path, tgt_path, src_lang='en_XX', tgt_lang='zh_CN', batch_size=16)
      

      总结:

      数据增强作用有限,接下来准备在相关任务数据上继续预训练。

      参考:

      1.一篇就够!数据增强方法综述
      2.回译
      3.mbart50
      4.机器翻译:基础和模型

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • [机器翻译] 21.7 mRASP2

      Contrastive Learning for Many-to-many Multilingual Neural Machine Translation
      github:

      摘要:

      现有的多语言模型聚焦于英语为中心的翻译,而非英语的方向远远落后。本文旨在一个多对多翻译系统,重点是非英语语言方向的质量。基于这样一个假设:通用的跨语言表示会导致更好的多语言翻译性能。为此提出了一种训练方法mRASP2,以获得单一统一的多语言翻译模型。mRASP2的核心在于如下两点:

      1. 通过对比学习拉近多语言表示对齐语义空间
      2. 同时使用平行和单语语料进行对齐增强

      结论:

      1. 对比学习确实能提升零资源翻译
      2. 使用单语数据,所有翻译方向上都取得了实质性的改进。
      3. 分析并可视化了本文方法,对比学习确实能够拉近不同语言语义的表征
      4. 未来打算使用更大数据集训练模型PC150

      方法:

      1.损失函数

      损失为交叉熵Lce和对比损失Lctr的加权和,|s|是平均句子长度,因为Lce是词级别的,而Lctr是序列级别的,两者有比例关系,因此要乘上平均句子长度。

      a2d8700b-7206-4977-91f6-c57372d76ad8-image.png
      xi,xj是平行语料。Lce计算常规decoder输出和label的交叉熵,旨在让解码器输出分布与真实分布一致。
      76cdb4ae-2613-4352-bda6-1376e9f2e31f-image.png
      而对比损失Lctr为了拉近语义空间中跨语言同义词的表征距离,并且拉远非同义词表征的距离。具体为:以某个样本点的源端向量表示为锚点,以该样本目标端的向量表征为正样本(过encoder),以同一个batch中其他样本点的目标端句子向量表示为负样本,最小化锚点和正样本的距离,最大化锚点和所以负样本的距离。
      f86c2f6d-9193-4f76-99fb-b43c8e4be414-image.png
      3e554e43-071a-47bc-913d-badf52716816-image.png
      其中距离使用的是余弦距离,分子是锚点和正例的距离,分母是所有负例和锚点的距离和,通过最小化Lctr就能达到拉近同义词表征、拉远非同义词表征的目的。

      引入对比学习,可以在不降低其他翻译方向的基础上,提高零资源翻译的性能。

      2.对齐增强

      b7f60901-713d-41d6-9743-a0e50cba1b23-image.png
      其中距离使用的是余弦距离,分子是锚点和正例的距离,分母是所有负例和锚点的距离和,通过最小化Lctr就能达到拉近同义词表征、拉远非同义词表征的目的。

      实验结果

      相比多语言基线模型m-Transformer,mRASP2在表中的10个方向上都有显著的提升。

      c14281db-4865-48c7-a4fc-66f7c84584e5-image.png
      在无监督翻译(至少一端的语料在预训练时出现过)上平均超过了基线十多点。
      b78da7d7-a98a-4690-89c6-aba3182157f4-image.png
      217ae51b-2072-4bbb-9993-445fe6716c53-image.png
      即使是在零资源翻译(非英语对翻译)上性能也很卓越,和桥接模型差不多(pivot)。
      14767123-15e4-477a-93e7-00d71dfbeb08-image.png

      可视化分析

      dd1b8ef1-6736-44f4-a529-80d67b4bea61-image.png
      使用T-SNE对英、日、德三种语言同义句的语义空间表征降维后可视化,发现使用mRASP(b)比基线transformer更好的拉近了多语言同义句的语义表征。

      个人总结

      对比学习yyds,接下来准备找代码试试。

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • [机器翻译] 21.1 字节跳动的mRASP预训练模型

      1.引言

      最近在看机器翻译文献时,常常望卡兴叹,尤其是facebook是真的壕,训练25种语言的mBart就用256张卡训练了20天,更不用说是mBart50。偶然发现这篇字节的mRASP( Random Aligned Substitution Pre-training )模型号称只需要8卡一周,简直太香了!(还是跑不起啊orz)论文为:Pre-training Multilingual Neural Machine Translation by Leveraging Alignment Information,内容如下:

      2.摘要:

      本文想构建一个统一的机器翻译模型,在提供任意语言对的情况下,可以快速适应新语言。于是提出一种通用的多语言机器翻译预训练模型:mRASP(多语言随机对齐预训练),在32种语言上进行预训练(双语数据),然后在42个翻译方向上进行微调,结果证明在低、中、高乃至零资源翻译上都有非常大的提升。本文首次验证多语言模型能提升富资源语言的效果。

      3.结论:

      mRASP可以使跨语言的同义词在嵌入空间上接近,在低、中、高和零资源数据上证明了模型效性。通过分析实验,发现对齐信息确实能不同语言语义上的鸿沟,并提升性能。
      未来工作是探索更多词对齐的方法,并在大规模数据上预训练进一步提升性能。

      4.介绍:

      1.本文认为预训练模型在nmt任务上的限制在于:
      (1)预训练的bert不能直接微调到nmt,除非用些复杂的办法。
      (2)预训练目标和下游任务(nmt)的训练目标有差异:如mass、mbart使用自编码器(降噪),和翻译任务不同,因此微调之后收益有限。
      (3)现有的多语言预训练方法仅能提升中、低资源翻译,而非任意语料对,尤其是对富资源上效果没有显著提升。(想想看人类学会多种语言后再学其他语言应该会很快)
      2.本文使用随机对齐替换使模型能弥合跨语言的鸿沟(见下),充分利用多语言知识,使得相同语义的语言在表征空间接近。mRASP在极端缺少平行语料(<10w),能达到22bleu。
      3.提出了异国翻译的四种分类法:
      (1)Exotic Pair:微调时的源语言和目标语言在预训练时各自单独出现过,但是没有成对训练;
      (2)Exotic Source:微调时的源语言没有在预训练时出现,只预训练过目标语言;
      (3)Exotic Target:微调时的目标语言没有在预训练时出现,只预训练过源语言;
      (4)Exotic Full:微调的两端语言在预训练中都没出现过(巨难);
      4.贡献
      (1)使用上亿对双语语料进行预训练,而不像其他模型一样用大量单语预训练。本文认为预训练和微调有一致的目标有利于nmt提升;
      (2)提出RAS,能够弥合跨语言的语义空间;
      (3)在42个方向上取得巨大提升,在预训练中源、目标语言都没有的极端情况(Exotic Full)取得14的bleu,在富语言en-fr上能进一步取得提升44.3bleu。

      5.模型:

      5.1.结构

      采用transformer-large,编码器解码器各6层,嵌入维度1024,14个head,激活函数换为GeLU,并使用可学习的位置嵌入。

      5.2.随机对齐替换

      不多说,先上图:
      b1d06413-2d77-4f37-a8f3-c406d2f3364f-image.png
      源句是:“ I like singing and dancing”,目标句是:“J’adore chanter et danser <EOS>”
      随机对齐替换就是无监督MUSE方法构建词典,然后随机替换掉源句种的“singing ”和“dancing”,编码器输入变为:“I like chanter and danser”,解码器的生成目标不变。
      我们知道一个词的词义是由其上下文决定的,因此把“chanter ”放到和“singing”同样的语境下,他们在嵌入空间的距离就拉近了,从而达到跨语言语义相近的目的。
      换成公式就是如下:
      8d978d61-0565-4592-b493-281e17cda3d7-image.png
      L={L1,…Lm}为预训练的语言集合,xi代表语言Li中的某个句子。Dij是平行语料,N是平行语料数。C是对齐函数,用于把源句中的单词替换为随机语言对应的词。在翻译方向为(xj,xi)时,目标函数使源语句xj在经随机替换后C(xj)条件下,得到翻译结果xi的概率最大,即最小化化负对数似然。

      5.3.语言标识

      为区分不同翻译对,在源和目标语句之前简单添加语言标识:
      460ca861-f2de-4cd7-ab57-2ccf785d5373-image.png

      5.4.灵感来源:

      最近的工作证明,跨语言模型预训练可能是一种更有效的方法来进行表征学习。然而
      在预训练时,跨语言信息是从共享子词表获得的,有如下局限:
      (1)共享词汇表非常系数,尤其是在不同的语言对上(形态上完全不一样,如英汉)
      (2)即使是相同的子词,在不同语言中也可能表示不同意思。
      (3)参数共享的方法缺乏明确的监督信号,来引导跨语言中相同意思词共享相同的语义空间
      因此本文为了弥合跨语言语义的鸿沟,提出了RAS随机对齐替换的方法。

      5.5 PC32(Parallel Corpus 32)

      收集了32个英文为中心的语言,64个翻译方向,统称为PC32,共包含197m平行语料

      792028c4-35ac-4911-9019-382eb1afe564-image.png

      5.6 预训练细节

      词汇表:
      使用联合词汇表,用共享bpe,32k次合并操作。数据使用全部平行语料和额外的1m单语数据。并且为了平衡不同语言的词汇表大小,在最大语料量语言的基础上,对其他低资源语言进行过采样,使得每个token出现数超过20,最终子词词汇表大小是64808。
      参数
      Adam优化器,eps= 1e − 8, β2 = 0.98,warmup=4000步,预训练15w次。
      RAS使用MUSE得到的English-X词典,取前1000个,用来随机替换源端的词,每个词有30%概率被替换。为解决一词多义,从候选词中随机选一个用来替换。
      结果:

      6. 微调结果

      在富资源语言上效果明显:
      4e54d55e-070d-49c7-8866-305f1f5f11b2-image.png
      在零资源语言上吊打直接训练。
      214ed334-b691-4813-8585-4be03fa5e532-image.png

      7.个人总结

      mRASP构建了一种通用机器翻译模型,能快速适应各种语言,且训练速度快,可以看出多语言机器翻译是大势所趋。不过本文使用的也是共享词汇表,在跨语系如中英时词汇表会很大很稀疏,使用类似通用词表嵌入的方法或许能在对不同语言词表解耦的同时,进一步拉近语义空间。

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • [低资源机器翻译综述]:A Survey on Low-Resource Neural Machine Translation

      摘要

      神经机器翻译效果非常好,但需要大量的平行语料,因此有了低资源翻译的研究。
      本文按照按数据的利用对低资源翻译分为3类:

      1. 利用单语数据
      2. 利用辅助语言
      3. 利用多模态数据

      01d786ae-0fe1-4346-a89f-abec8bfdd27d-image.png

      结论和未来方向

      目前还有如下开放问题:

      1. 在多语言迁移学习中,尚不知道应该用多少语言、哪些语言。
      2. 在迁移学习中如何处理未见过语言的词表
      3. 如何高效选择数轴语言
      4. 双语词典非常有用且易得,目前的研究主要用在源语言和目标语言上,如何用在多语言迁移学习中的低资源和辅助语言上
      5. 考虑到多模态数据,语音有提升翻译性能的潜力,同时也有许多限制,比如有同音异字
      6. 目前在低资源翻译上取得成功的方法,或者有大量单语语料,或者有相似的富资源语言。如果两个都没有怎么办,如阿迪格语和锡伯语。

      2.利用单语数据

      ba212708-5447-4b29-9e46-fb9a64a08a6f-image.png

      2.1 回译、前向翻译

      回译:用tgt2src的反向翻译模型将目标语言的单语语料t转换为源语言,从而得到伪平行数据Bp(tgt2src(t),t)。
      前向翻译:相反,用src2tgt的正向翻译模型将源语言的单语语料s转换为目标语言,从而得到伪平行数据Bp’(s, src2tgt(s))。
      将产生的伪数据Bp, Bp’和真的平行语料Dp混合后训练正向模型有助于性能提升。
      除了使用术搜索生成伪数据外,还有许多方法:

      (1)根据输出概率分布随机采样
      (2)在源语言添加噪声,再结合术搜索生成
      (3)对术搜索生成的句子预先添加标签
      随机采样和加噪声只在富资源语言上奏效,而第三种预添加标签在富、低资源翻译上都表现最好。除此之外,在低资源翻译上,将目标语言拷贝到源语言也能进一步提升翻译质量。

      2.2 双向联合训练

      (1)考虑到源语言和目标语言都很稀缺的情况,可以使用对偶学习,将源语言x经前向模型得到y’,再输入反向模型回译成x’,优化x和x’的重建损失。后面有人提出multi-agent进一步提升对偶学习。,
      (2)直观上,更好的回译模型带来更好的伪数据,从而训练出更好的翻译系统。使用迭代回译可以重复执行回译、训练的过程,从而使模型生成越来越高质量的句子,得到更好的NMT系统,流程如下图:
      556c2cb0-3b6d-41df-aa20-6febf9db3626-image.png

      2.3无监督NMT

      为处理零资源翻译的场景,常用的步骤包含两个部分:
      (1)双语对齐,使模型能对齐两种语言:
      a.双语词嵌入
      b.降噪自编码器
      c.无监督统计机器翻译
      d.语言模型预训练
      (2)翻译提升,通过迭代学习提升翻译质量:
      a.迭代回译,见2.2
      b.过滤低质量的伪数据
      c.Loss种加正则,防止训练时遗忘双语嵌入
      d.同时用统计、神经机器翻译模型进行回译

      2.4语言模型预训练

      预训练语言模型能提升对语言的理解和生成能力,而NMT同时需要这两种能力,按是否联合训练编码器和解码器分为两类:
      (1)分离训练:如XLM
      (2)联合训练:如MASS,Bart,T5

      2.5利用相似语料

      相似语料即涉及相同实体的不同语言单语语料,可以从中挖掘隐含的平行语料。如LASER。

      2.6利用双语词典增强

      (1)用于稀有词翻译
      (2)逐词翻译
      (3)基于词典,缩小源语言和目标语言之间嵌入空间的差距

      2.7 小结

      以上方法可以组合使用,如回译和联合训练

      3. 利用辅助语言

      156eae12-d0f9-4378-8369-cd0777c0c157-image.png

      3.1 多语言训练:

      低资源语言对与其他语言对在一个模型中联合训练
      优点:
      (1)较训练多个模型,多语言训练显著降低训练时间,且容易维护
      (2)低资源语言可以受益于富资源语言
      (3)多语言模型有潜力做到零资源翻译
      相关工作可被分为:
      (1)参数共享(不共享、全部共享、部分共享)
      (2)针对低资源语言的设计
      a.辅助语言选择,尽量选择同一语系的富资源语言
      b.训练样本平衡,用基于温度的方法平衡富、低资源语言,使得模型不再偏好富资源语言
      c.辅助语言词重排序:预先对辅助语言重排词的顺序再进行翻译
      d.辅助语言的单语数据:用回译、跨语言预训练、元学习、无监督等方法提升低资源语言模型
      (3)零资源翻译
      假设模型学过x和英文的双向翻译,y和英文的双向翻译,即使模型没见过x和y的平行语料,模型也能进行x和y的双向翻译。

      3.2 迁移学习:

      即先训练通常包含富资源语言对的父母NMT模型,然后微调低资源语言对。
      共享词汇表不适用于将预先训练的父模型迁移到词汇表中有未见过文字的语言。为了解决这一问题,Kim等人提出学习未见语言和双语父模型的嵌入的跨语言线性映射。

      3.3 枢轴翻译:

      选择一种或多种枢轴语言作为源语言和目标语言之间的桥梁,利用源-枢轴和枢轴-目标数据来帮助源目标语言的翻译。有如下三种方式:
      (1)直接结合源-枢轴和枢轴-目标模型,逐个翻译
      (2)使用源-枢轴和枢轴-目标模型生成伪数据,用来训练源-目标模型
      (3)使用源-枢轴和枢轴-目标模型的参数,进行从源到目标语言的迁移学习

      4.利用多模态数据

      目前,图像-文本并行数据在NMT上的应用是有限的,因为这种图像-文本数据对于低资源语言来说总是很难收集。建立新的图像-文本数据集的一个可能的数据源是网站上的图像和相应的标题。
      对于只有语音而没有文本的语言,可以利用语音数据来进行翻译。

      5.数据集

      4fffeb5c-eaa7-46ed-9cd3-939124608219-image.png

      个人总结

      接下来我可以针对迁移学习的词表映射、多语言模型的部分参数共享、对偶学习、元学习这几个方面继续研读。

      参考

      A Survey on Low-Resource Neural Machine Translation

      posted in 语音识别与语义处理领域
      173****5160
      173****5160
    • NAG优化器

      最近在看fairseq源码时发现NAG优化器 (Nesterov Accelerate gradient)的实现与torch自带的有些许不一样,于是打算查下资料了解清楚。

      先回忆下Momentm,该梯度下降法引入动量的概念,使用β对历史梯度进行滑动指数加权平均,最早的梯度衰减的最快,对当前更新影响小;反之,越接近当前的梯度对更新的影响越大,公式为:
      ~A1E~JC(`1PVA}6A{VX~1TO.png
      其中Vt、gt、g(θt)分别代表t时刻的速度、梯度、模型参数,μ是动量系数,lr是学习率。该方法的思想是对网络参数进行平滑处理,让梯度的摆动幅度不要太大。

      NAG类似Momentum,它们都是利用历史梯度来更新参数,区别在于,NAG先利用μVt,对θt进行部分更新得到θt+μVt,然后利用梯度g(θt+μVt)更新得到θt+1,其公式如下所示:
      0b548033-acf7-443c-a3e1-63dad71b448a-image.png
      此处ε是学习率。
      下图对Momentum和NAG作了形象解释:
      2f7cf5bf-0cd2-4372-be18-40232b3b8d45-image.png
      Momentum使用当前位置A处的速度Vt和梯度g(θt)直接更新到目的地C;而NAG从A点先沿着惯性方向走一小步到B,此处距C很接近了, 再利用B处的梯度g(θt+μVt)更新到C。

      论文中认为这样可以快速更新V,使得Nag比momentum更稳定,且更适合于大学习率的场景。除此之外,如果Nag用μVt更新到B点较差时,由于B点梯度g(θt+μVt)比momentum的g(θt)更大,因此Nag能更快往回修正到起始点A。

      言归正传,这是torch.optim.SGD的公式和代码[1]:
      bdefa8bc-17ff-49d9-be5a-36d033e48cae-image.png
      42f9a14a-577f-46d5-bf01-f3d23ef7036b-image.png

      这是fairseq.optim.nag的公式和代码[2]:
      ca9833e5-5ed5-40f2-bb69-b42ebd434cf7-image.png
      df40b1ba-49e1-47a5-a8e3-897d64af1854-image.png
      可以看出两者实际上还是有些不同,而Fairseq的nag实际上和论文的公式基本一致,[3]中有推导:
      11dce8f3-c11a-4070-9936-1e25351d8ab5-image.png
      其中的β就是本文的动量系数μ,先对θt+βVt做了代换得到θt’后,最后将θt’当成待更新的参数θt,也就是每次更新的始终是θt+βVt,关于这个的解释见下图及[4]:
      f74fee8c-81c6-4dcf-9963-d0b8695ee67d-image.png

      总之,nag优化器能加速收敛,且使用很大的学习率也很稳定,难怪fairseq里面ConvS2S能使用0.5的学习率。

      [1]torch sgd
      [2]fairseq nag
      [3]深度学习中优化方法
      [4]CS231n Convolutional Neural Networks for Visual Recognition

      posted in 语音识别与语义处理领域
      173****5160
      173****5160