Navigation

    Gpushare.com

    • Register
    • Login
    • Search
    • Popular
    • Categories
    • Recent
    • Tags

    paddle2.x版roformer

    技术交流
    1
    1
    42
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • 183****0229
      183****0229 last edited by 183****0229

      这周花了点时间将pytorch版的roformer转化成了paddle版本的。
      https://github.com/PaddlePaddle/PaddleNLP/pull/804
      写个帖子记录一下提交PR的过程及过程中遇到的坑。

      坑

      • 坑1:PaddleNLP库不像huggingface/transformers有个贡献指南文档。
        因此在贡献的时候,我参考了下paddlepaddle的贡献指南文档。
      • 坑2:提交的时候报错yapf错误。
        后来发现pre-commit的时候,会使用yapf进行更新项目中的代码,然后还需要重新git add .才能记录上被yapf修改过的文件,这样才能提交成功。

      过程

      # 首先fork https://github.com/PaddlePaddle/PaddleNLP
      # 然后克隆到本地
      git clone https://github.com/【你的用户名】/PaddleNLP
      cd PaddleNLP
      # 使用 git checkout -b 创建并切换到新分支。
      git checkout -b 【分支的名字】
      # 安装pre-commit
      pip install pre-commit
      # 给本地分支安装pre-commit 
      pre-commit install
      # 修改文件后先pre-commit格式化文件规范
      pre-commit
      # 添加并commit修改的文件
      git add .
      git commit -m "fix xxx" 
      # 推送到远程分支
      git push
      

      由于paddlepaddle2.x版本与pytorch版本的API差不多一致,因此我们模型转换的时候其实很简单。可以对着pytorch的代码直接对应修改。
      例如:
      pytorch roformer中的

          @staticmethod
          def apply_rotary_position_embeddings(
              sinusoidal_pos, query_layer, key_layer, value_layer=None
          ):
              # https://kexue.fm/archives/8265
              # sin [batch_size, num_heads, sequence_length, embed_size_per_head//2]
              # cos [batch_size, num_heads, sequence_length, embed_size_per_head//2]
              sin, cos = sinusoidal_pos.chunk(2, dim=-1)
              # sin [θ0,θ1,θ2......θd/2-1] -> sin_pos [θ0,θ0,θ1,θ1,θ2,θ2......θd/2-1,θd/2-1]
              sin_pos = torch.stack([sin, sin], dim=-1).reshape_as(sinusoidal_pos)
              # cos [θ0,θ1,θ2......θd/2-1] -> cos_pos [θ0,θ0,θ1,θ1,θ2,θ2......θd/2-1,θd/2-1]
              cos_pos = torch.stack([cos, cos], dim=-1).reshape_as(sinusoidal_pos)
              # rotate_half_query_layer [-q1,q0,-q3,q2......,-qd-1,qd-2]
              rotate_half_query_layer = torch.stack(
                  [-query_layer[..., 1::2], query_layer[..., ::2]], dim=-1
              ).reshape_as(query_layer)
              query_layer = query_layer * cos_pos + rotate_half_query_layer * sin_pos
              # rotate_half_key_layer [-k1,k0,-k3,k2......,-kd-1,kd-2]
              rotate_half_key_layer = torch.stack(
                  [-key_layer[..., 1::2], key_layer[..., ::2]], dim=-1
              ).reshape_as(key_layer)
              key_layer = key_layer * cos_pos + rotate_half_key_layer * sin_pos
              if value_layer is not None:
                  # rotate_half_value_layer [-v1,v0,-v3,v2......,-vd-1,vd-2]
                  rotate_half_value_layer = torch.stack(
                      [-value_layer[..., 1::2], value_layer[..., ::2]], dim=-1
                  ).reshape_as(value_layer)
                  value_layer = value_layer * cos_pos + rotate_half_value_layer * sin_pos
                  return query_layer, key_layer, value_layer
              return query_layer, key_layer
      

      paddle roformer

          @staticmethod
          def apply_rotary_position_embeddings(sinusoidal_pos,
                                               query_layer,
                                               key_layer,
                                               value_layer=None):
              # https://kexue.fm/archives/8265
              # sin [batch_size, num_heads, sequence_length, embed_size_per_head//2]
              # cos [batch_size, num_heads, sequence_length, embed_size_per_head//2]
      
              sin, cos = paddle.chunk(sinusoidal_pos, 2, axis=-1)
      
              # sin [θ0,θ1,θ2......θd/2-1] -> sin_pos [θ0,θ0,θ1,θ1,θ2,θ2......θd/2-1,θd/2-1]
              sin_pos = paddle.reshape(
                  paddle.stack(
                      [sin, sin], axis=-1), sinusoidal_pos.shape)
              # cos [θ0,θ1,θ2......θd/2-1] -> cos_pos [θ0,θ0,θ1,θ1,θ2,θ2......θd/2-1,θd/2-1]
              cos_pos = paddle.reshape(
                  paddle.stack(
                      [cos, cos], axis=-1), sinusoidal_pos.shape)
              # rotate_half_query_layer [-q1,q0,-q3,q2......,-qd-1,qd-2]
      
              rotate_half_query_layer = paddle.reshape(
                  paddle.stack(
                      [-query_layer[:, :, :, 1::2], query_layer[:, :, :, 0::2]],
                      axis=-1),
                  query_layer.shape, )
              query_layer = query_layer * cos_pos + rotate_half_query_layer * sin_pos
              # rotate_half_key_layer [-k1,k0,-k3,k2......,-kd-1,kd-2]
      
              rotate_half_key_layer = paddle.reshape(
                  paddle.stack(
                      [-key_layer[:, :, :, 1::2], key_layer[:, :, :, 0::2]], axis=-1),
                  key_layer.shape, )
              key_layer = key_layer * cos_pos + rotate_half_key_layer * sin_pos
              if value_layer is not None:
                  # rotate_half_value_layer [-v1,v0,-v3,v2......,-vd-1,vd-2]
                  rotate_half_value_layer = paddle.reshape(
                      paddle.stack(
                          [-value_layer[:, :, :, 1::2], value_layer[:, :, :, 0::2]],
                          axis=-1),
                      value_layer.shape, )
                  value_layer = value_layer * cos_pos + rotate_half_value_layer * sin_pos
                  return query_layer, key_layer, value_layer
              return query_layer, key_layer
      
      

      RoFormer

      模型简介

      RoFormer (RoFormer: Enhanced Transformer with Rotary Position Embedding)是一个带有旋转位置嵌入(RoPE)的MLM预训练语言模型。 RoPE是一种相对位置编码方法,具有良好的理论特性。其主要思想是根据绝对位置将上下文嵌入(transformer中的 q,k)乘以旋转矩阵。可以证明上下文嵌入的内积将仅取决于相对位置。
      RoPE 是唯一可用于线性注意力的相对位置嵌入。更多详情请参考论文或原博客。EleutherAI还发布了一篇博客,其中包含有关 RoPE 的直观解释和实验。

      本项目是RoFormer在 Paddle 2.0上的开源实现,包含了THUCNews分类任务的微调代码。

      快速开始

      THUCNews分类任务数据

      THUCNews分类任务所含数据集已在paddlenlp中以API形式提供,无需预先准备,使用run_thucnews.py执行微调时将会自动下载。

      执行Fine-tunning

      启动Fine-tuning的方式如下:

      unset CUDA_VISIBLE_DEVICES
      python -m paddle.distributed.launch --gpus "0" run_thucnews.py \
          --model_type roformer \
          --model_name_or_path roformer-chinese-base \
          --max_seq_length 256 \
          --batch_size 64   \
          --learning_rate 2e-5 \
          --num_train_epochs 3 \
          --logging_steps 1 \
          --save_steps 500 \
          --output_dir ./tmp/ \
          --device gpu \
          --use_amp False
      

      其中参数释义如下:

      • model_type 指示了模型类型,使用RoFormer模型时设置为roformer即可。
      • model_name_or_path 指示了某种特定配置的模型,对应有其预训练模型和预训练时使用的 tokenizer。若模型相关内容保存在本地,这里也可以提供相应目录地址。注:roformer-chinese-base等对应使用的预训练模型转自huggingface/transformers,具体可参考当前目录下converter中的内容。
      • max_seq_length 表示最大句子长度,超过该长度将被截断。
      • batch_size 表示每次迭代每张卡上的样本数目。
      • learning_rate 表示基础学习率大小,将于learning rate scheduler产生的值相乘作为当前学习率。
      • num_train_epochs 表示训练轮数。
      • logging_steps 表示日志打印间隔。
      • save_steps 表示模型保存及评估间隔。
      • output_dir 表示模型保存路径。
      • device 表示训练使用的设备, 'gpu’表示使用GPU, 'xpu’表示使用百度昆仑卡, 'cpu’表示使用CPU。
      • use_amp 指示是否启用自动混合精度训练。

      基于roformer-chinese-base在THUCNews分类任务上Fine-tuning后,在验证集上有如下结果:

      Task Metric Result
      THUCNews Accuracy 0.98
      1 Reply Last reply Reply Quote 1
      • First post
        Last post