[go: up one dir, main page]

训练 GPT-neox (1) ----环境配置

本章节仅 针对于训练环境配置进行记录与说明,对于训练中的工具使用,demo,优化,将在后续内容讨论。

1. EC2 的选择

对于小规模的GPT-neox,博主最开始是以省钱为目的出发的,因此选择的是 Nvidia T4 GPU,即 AWS g4dn系列的机器,即可支持自定义小规模的transformer模型。本篇章后续的所有依赖,也都基于 AWS g4dn的机器。(注意T4不支持 Flash-Attention 加速,Flash-Attention 仅支持 Ampere 架构)。 在部署环境测试的时候,可以选择最小的g4dn.xlarge,后续训练有需要,再进行扩容。

2.OS的选择

Llama3部署环境 相同,不建议大家 使用不含 驱动的 AWS linux,因为需要解决的冲突较多,博主继续选择了与部署Llama3 一样的AMI: Deep Learning OSS Nvidia Driver AMI GPU TensorFlow 2.16 (Amazon Linux 2) 20240509

3. python 依赖安装

注意!!!与Llama3部署环境 不同,由于训练时需要使用 apex 框架,因此对cuda和torch的版本有要求,默认pip 安装的 torch 版本 为 2.3.0,版本过高,如果使用该版本,则需要重新安装 cuda。因此博主使用匹配 当前os的torch 版本。

pip install torch torchvision torchaudio accelerate -i https://pypi.tuna.tsinghua.edu.cn/simple

除此以外,需要 安装python开发的工具包,以后续编译 apex。

sudo yum install python3-devel

4. apex 安装

Nvidia apex 是一个强大的工具包,可以进行混合精度训练与分布式训练等,显著的提高计算效率,GPT-neox也依赖于 apex。

需要注意,安装 apex 请通过官网下载 https://github.com/NVIDIA/apex

不要 使用 pip install(因为pip装上的并不是你以为的apex)。

a) clone repo到服务器 git clone https://github.com/NVIDIA/apex

b) 修改 setup.py 中,对 cuda 版本与 torch.version.cuda 版本的校验逻辑,注释 setup.py 的第 178 行。不然则会raise版本不匹配的错误,编译时退出。

c) 根据 “apex/README.md” 中指导安装 apex pip install -v --disable-pip-version-check --no-cache-dir --no-build-isolation --config-settings "--build-option=--cpp_ext" --config-settings "--build-option=--cuda_ext" ./

4. GPT-neox 依赖与环境修改

在配置你自己的模型并进行训练前,需要对gpt neox中的极小一部分 src code进行修改,以便后续编译。

a) clone repo 到服务器 https://github.com/EleutherAI/gpt-neox

b) 安装依赖 pip install -r requirements/requirements.txt, 这里不要使用国内的镜像源,因为requirement里面需要下载 DeepSpeed 的repo。如果出现网络问题,多次尝试即可。(泪目,国内开发者伤不起)

c) 修改 gpt-neox/megatron/data 中的 Makefile

我们需要 data 文件下的 src 帮我们处理自己的训练数据,需要用到里面的helpers.cpp。而当前 EC2环境下,python3-config 并不是我们需要的 python3.10版本的解释器配置,python-config才是,因此替换python3-configpython-config

修改后可以 make 尝试编译,然后使用python3 import helpers,如果不报错,则修改成功。

5. 训练数据准备并 Pretokenize

训练的数据集可以是任何数据集,但是需要自己进行处理,process代码已经在 gpt neox的repo里面了。需要注意 a 和 b 步骤需要 连接 huggingface,而CN EC2是不行的,所以博主是在本地获取后,scp 到了EC2上。为啥我们要 pre tokenize 数据呢,还不是因为 CN 的环境不能连接 hugging face。

a) 获取训练数据,博主使用了 wiki的数据进行测试。可以直接使用以下代码获取。

from datasets import load_dataset

dataset = load_dataset("wikitext", "wikitext-103-raw-v1")

with open("wikitext_train.txt", "w") as f:
    for line in dataset["train"]:
        f.write(line["text"] + "\n")

with open("wikitext_validation.txt", "w") as f:
    for line in dataset["validation"]:
        f.write(line["text"] + "\n")

with open("wikitext_test.txt", "w") as f:
    for line in dataset["test"]:
        f.write(line["text"] + "\n")

b)获取词汇表文件和合并文件

这取决于你使用什么 Tokenizer,博主使用 GPT2Tokenizer,可以直接使用以下代码获取 vocab.json 和 merges.txt。

from transformers import GPT2Tokenizer

tokenizer = GPT2Tokenizer.from_pretrained("gpt2")

tokenizer.save_vocabulary(".")

c) Pretokenize 数据,README里有哦

python3 tools/datasets/preprocess_data.py --input ./tiashi/wikitext_train.txt --output-prefix ./tiashi/mydataset --vocab ./tiashi/vocab.json --merge-file ./tiashi/merges.txt --dataset-impl mmap --tokenizer-type GPT2BPETokenizer --append-eod

会生成 mydataset_text_document.bin 与 mydataset_text_document.idx 两个文件,在后续 模型的config中,使用

"data-path": "./tiashi/mydataset_text_document"
6. 配置你的模型

模型的参数配置部分后续会单独开一个article进行讲解,本章只对环境和流程进行详述,给出博主使用的一个17M 参数的用例:

{
  "pipe_parallel_size": 1,
  "model_parallel_size": 1,

  # model settings
  "num_layers": 6,
  "hidden_size": 512,
  "num_attention_heads": 8,
  "seq_length": 2048,
  "max_position_embeddings": 2048,
  "pos_emb": "rotary",
  "no_weight_tying": true,
  "gpt_j_residual": false,
  "output_layer_parallelism": "column",

    #"attention_config": [[["flash"], 6]],

  "scaled_upper_triang_masked_softmax_fusion": false,
  "bias_gelu_fusion": false,
  "rope_fusion": false,
  "layernorm_fusion": false,
  
  "vocab_file": "./tiashi/vocab.json",
  "save": "./tiashi/tom-19M_checkpoints",
  "load": "./tiashi/tom-19M_checkpoints",

  "merge_file": "./tiashi/merges.txt", 
  "data-path": "./tiashi/mydataset_text_document",
  # init methods
  "init_method": "small_init",
  "output_layer_init_method": "wang_init",

  "optimizer": {
    "type": "Adam",
    "params": {
      "lr": 0.001,
      "betas": [0.9, 0.95],
      "eps": 1.0e-8,
    }
  },
  "min_lr": 0.0001,

  # for all zero_optimization options, see https://www.deepspeed.ai/docs/config-json/#zero-optimizations-for-fp16-training
  "zero_optimization": {
    "stage": 1,
    "allgather_partitions": True,
    "allgather_bucket_size": 500000000,
    "overlap_comm": True,
    "reduce_scatter": True,
    "reduce_bucket_size": 500000000,
    "contiguous_gradients": True,
  },

  "train_micro_batch_size_per_gpu": 20, #32,
  "gradient_accumulation_steps": 1,
  "data_impl": "mmap",
  "num_workers": 1,

  # activation checkpointing
  "checkpoint_activations": true,
  "checkpoint_num_layers": 1,
  "partition_activations": true,
  "synchronize_each_layer": true,

  # regularization
  "gradient_clipping": 1.0,
  "weight_decay": 0.1,
  "hidden_dropout": 0,
  "attention_dropout": 0,

  # precision settings
  "fp16": {
    "fp16": true,
    "enabled": true,
    "loss_scale": 0,
    "loss_scale_window": 1000,
    "initial_scale_power": 12,
    "hysteresis": 2,
    "min_loss_scale": 1,
  },

  "train_iters": 143000,
  "lr_decay_iters": 143000,
  "distributed_backend": "nccl",
  "lr_decay_style": "cosine",
  "warmup": 0.01,
  "checkpoint_factor": 1000,
  "eval_interval": 500000,
  "eval_iters": 10,

  "log_interval": 50,
  "steps_per_print": 10,
  "wall_clock_breakdown": true,
  
  "tensorboard-dir": "./tensorboard",
  "log_dir": "./logs",

  # additional deepspeed args not specified above
  "deepspeed_extra_args": {
    "comms_logger": {
        "enabled": true,
        "verbose": true,
        "prof_all": true,
        "debug": false
    },
  }

}
7. 训练你的模型

直接跑 nohup python3 deepy.py train.py --conf_dir configs tom-19M.yml > runlog.log 2>&1 &

可以在 日志中看到 模型的训练情况。博主使用了 tensorboard 对性能进行可视化,关于模型训练过程的调优和 辅助工具的使用,同样会在后续单独写article进行讨论。

8. 调用你的模型

模型在训练结束以后,会存于 checkpoint里面,可以选择最新的一个 checkpoint文件夹,作为模型调用的文件目录。需要注意的是,这里的模型训练好都是 .pt 的文件,而模型config 则是我们之前 的 yml 文件,也会在 checkpoint文件夹中保存一份。

其中,模型状态文件为:mp_rank_00_model_states.pt,zero_pp_rank_{}_mp_rank_00_optim_states.pt 是优化器状态文件,推理阶段仅需要 mp_rank_00_model_states.pt即可。

这里的config.json是博主自己后续生成的,其实不需要。

调用模型的代码如下:

import torch
from transformers import GPTNeoXConfig, GPTNeoXForCausalLM, GPT2Tokenizer
import yaml

# 指定模型配置文件路径
config_path = "/home/ec2-user/gpt-neox/tiashi/tom-small_checkpoints/global_step30000/configs/tom-small.yml"

# 将 YAML 文件加载为字典
with open(config_path, 'r') as file:
    config_data = yaml.safe_load(file)

config = GPTNeoXConfig(**config_data)

# 创建模型实例
model = GPTNeoXForCausalLM(config)
model_path = "/home/ec2-user/gpt-neox/tiashi/tom-small_checkpoints/global_step30000/"
# 加载模型权重
state_dict = torch.load(f'{model_path}mp_rank_00_model_states.pt', map_location=torch.device('cuda'))
model.load_state_dict(state_dict['module'], strict=False)

# 将模型设为评估模式
model.eval()

#from transformers import GPTNeoXTokenizer

# 加载GPT-NeoX的tokenizer (假设你已经训练并保存了一个tokenizer)
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
#tokenizer = GPTNeoXTokenizer.from_pretrained('gpt2')

# 输入示例
input_text = "Game"
inputs = tokenizer(input_text, return_tensors="pt")

# 生成输出
with torch.no_grad():
    outputs = model.generate(inputs.input_ids, max_length=50)

# 解码输出
generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(generated_text)

运行脚本,即可得到模型的输出。评测模型的性能,如何使用harness框架,同样将在后续article中再进行详述。

附录

环境配置中常见的错误见:gpt-neox via CN AWS EC2 部署环境问题汇总,后续会逐步完善。

祝大家生活愉快。