训练的输入长度=source的长度+target的长度
–pre_seq_len:pre_seq_len的取值范围一般是1到512,它表示自然语言指令的长度,即输入序列中的前pre_seq_len个token,具体的值需要根据自然语言指令的长度和复杂度来确定。一般来说,指令越长越复杂,pre_seq_len就需要越大,以便模型能够充分理解指令的含义。但是,pre_seq_len也不能太大,否则会占用过多的输入序列长度,导致生成内容过于单一或重复。因此,pre_seq_len的取值需要在保证指令完整性和生成多样性之间进行权衡。一种可能的方法是,根据不同的指令类型设置不同的pre_seq_len值,例如,对于简单的指令,如“生成一个笑话”,可以设置pre_seq_len为4;对于复杂的指令,如“生成一个关于环保主题的故事”,可以设置pre_seq_len为16。当然,这些值也需要根据实际的效果进行调整和优化。
–pre_seq_len和max_source_length的含义是差不多的,或者取值是可以参照的?不完全是的,pre_seq_len和max_source_length的含义是不同的,但是它们之间有一定的关系。pre_seq_len是指自然语言指令的长度,而max_source_length是指整个输入序列的最大长度。一般来说,pre_seq_len应该小于或等于max_source_length,因为输入序列除了包含指令之外,还可能包含其他内容,例如上下文信息或对话历史。如果pre_seq_len大于max_source_length,那么模型就无法接收到完整的指令,也就无法正确地生成输出内容。因此,pre_seq_len和max_source_length的取值需要协调一致,以保证模型能够有效地利用输入信息。
P-Tuning的时候的 soft prompt的长度,越大可微调的参数越多
PRE_SEQ_LEN=128
LR=2e-2
NUM_GPUS=2
torchrun --standalone --nnodes=1 --nproc-per-node=$NUM_GPUS main.py \
--do_train \
--train_file AdvertiseGen/train.json \
--validation_file AdvertiseGen/dev.json \
--preprocessing_num_workers 10 \
--prompt_column content \
--response_column summary \
--overwrite_cache \
--model_name_or_path /usr/local/serving/models/chatglm/chatglm2-6b \
--output_dir output/adgen-chatglm2-6b-pt-$PRE_SEQ_LEN-$LR \
--overwrite_output_dir \
--max_source_length 64 \
--max_target_length 128 \
--per_device_train_batch_size 1 \
--per_device_eval_batch_size 1 \
--gradient_accumulation_steps 16 \
--predict_with_generate \
--max_steps 3000 \
--logging_steps 10 \
--save_steps 1000 \
--learning_rate $LR \
--pre_seq_len $PRE_SEQ_LEN \
--quantization_bit 4
这段代码使用了 `torchrun` 命令来以分布式训练的方式运行 `main.py` 文件。具体来说,代码参数解释如下:
- `--standalone` 表示以独立模式启动分布式训练(即在同一台机器上的多个 GPU 上运行)。如果在多个机器上运行,则需要设置其他参数,例如 `--nnodes` 和 `--nproc-per-node` 等。
- `--nnodes` 指定节点数。在这个例子中,只有一个节点,所以设置为 1。
- `--nproc-per-node` 指定每个节点上的进程数。在这个例子中,只使用一个 GPU,所以设置为 1。
- `--do_train` 表示执行训练任务。
- `--train_file` 指定训练数据文件路径。
- `--validation_file` 指定验证数据文件路径。
- `--preprocessing_num_workers` 指定数据预处理时的工人数。
- `--prompt_column` 指定输入数据中输入文本所在的列。
- `--response_column` 指定输出数据中输出文本所在的列。
- `--overwrite_cache` 表示覆盖缓存文件。
- `--model_name_or_path` 指定使用的预训练模型的名称或路径。
- `--output_dir` 指定输出目录,即训练结果和模型保存目录。
- `--overwrite_output_dir` 表示覆盖输出目录。
- `--max_source_length` 指定输入文本的最大长度。
- `--max_target_length` 指定输出文本的最大长度。
- `--per_device_train_batch_size` 指定每个 GPU 上每次训练时的批量大小。
- `--per_device_eval_batch_size` 指定每个 GPU 上每次验证时的批量大小。
- `--gradient_accumulation_steps` 指定累积多少个梯度之后再进行一次反向传播。
- `--predict_with_generate` 表示在预测时使用生成模式。
- `--max_steps` 指定最大训练步数。
- `--logging_steps` 指定多少步记录一次日志。
- `--save_steps` 指定多少步保存一次模型。
- `--learning_rate` 指定初始学习率。
- `--pre_seq_len` 指定预处理时选取的序列长度。
- `--quantization_bit` 指定量化位数。
该命令将会在 PyTorch 1.7 或更高版本上运行。在此之前的版本中,可能需要单独设置分布式环境,享用多 GPU 训练所带来的好处。
好的,请容许我再详细解释一下多级多卡运行的调整步骤:
假设我们有两台机器 m1 和 m2,每台机器上有两块 GPU,我们希望在这两台机器上使用 PyTorch 的分布式训练模式运行代码:
1. 安装 PyTorch
首先在 m1 和 m2 上安装 PyTorch,并确保安装相同版本的 PyTorch。
2. 设置环境变量
在每台机器上设置相同的环境变量,以指定 PyTorch 使用分布式训练模式:
export WORLD_SIZE=
export RANK=
export MASTER_ADDR=
export MASTER_PORT=
其中,`number_of_processes` 是进程数,假设使用四个 GPU,所以 `number_of_processes` 是 4 。`rank_of_current_process` 是当前进程的排名,假设在 m1 中的排名为 0 和 1,m2 中的排名为 2 和 3。`address_of_master_machine` 是主节点的 IP 地址或主机名,假设主节点为 m1。`port_of_master_machine` 是主节点的端口号,假设主节点端口号为 1234。
3. 同步时间
确保所有机器的系统时间是同步的,可以使用如下命令同步时间:
sudo ntpdate cn.pool.ntp.org
4. 配置 SSH 免密登录
在每台机器上都需要通过 SSH 连接到其他机器。为此,需要在每台机器上配置 SSH 免密登录,以便不需要密码就可以登录到其他机器。可以使用如下命令生成公私钥对:
ssh-keygen -t rsa -P “”
然后将生成的公钥复制到其他机器的 `authorized_hosts` 文件中。
5. 编写工作节点程序
在工作节点上,需要自己定义需要运行的 Python 脚本代码。例如,我们编写了 worker.py 文件:
```python
# worker.py
import torch
# 定义需要执行的 PyTorch 代码
def run():
rank = torch.distributed.get_rank()
print(f"Rank {rank} is running on {torch.cuda.device_count()} GPUs.")
if __name__ == '__main__':
# 设置分布式环境
torch.distributed.init_process_group(backend='nccl')
# 执行 PyTorch 代码
run()
可以发现,这段程序中主要定义了需要运行的 PyTorch 代码。在 main.py/dataload.py/… 中,您可以根据自己的需要修改和编写相应的代码,例如模型定义、数据加载等等。
在 m1 的启动终端中运行以下命令:
# 启动第一个进程
python -m torch.distributed.launch --nproc_per_node=2 --use_env --master_port=1234 --node_rank=0 worker.py &
# 启动第二个进程
python -m torch.distributed.launch --nproc_per_node=2 --use_env --master_port=1234 --node_rank=1 worker.py &
在 m2 的启动终端中运行以下命令:
# 启动第三个进程
python -m torch.distributed.launch --nproc_per_node=2 --use_env --master_addr=<m1-ip> --master_port=1234 --node_rank=2 worker.py &
# 启动第四个进程
python -m torch.distributed.launch --nproc_per_node=2 --use_env --master_addr=<m1-ip> --master_port=1234 --node_rank=3 worker.py &
注意:
--use_env
参数,以便子进程能够继承主节点的环境变量。--nproc_per_node
参数指定每台机器上的 GPU 数量。--node_rank
参数,对应上面步骤 2 中设置的当前进程的排名。启动后,各个进程就会分别运行 worker.py 文件中定义的函数,并借助分布式环境来执行其任务。
@dataclass 是 Python 3.7 及更高版本中提供的一个装饰器。它能够自动为类生成一些常用的方法和属性,例如 `__init__` 方法、`__repr__` 方法以及属性的 getter 和 setter 方法。
在上面的代码中,@dataclass 被用于定义了两个类:ModelArguments 和 DataTrainingArguments。
这样使用 @dataclass 装饰器的类可以省略一些常见的代码,例如不再需要手动定义 init 方法、repr 方法和 getter/setter 方法。取而代之的是,使用 @dataclass 装饰器后, Python 会自动根据类的字段生成这些方法。
此外,通过给字段添加 field() 函数的调用,还可以为字段提供额外的元数据,例如字段的默认值和帮助文档。field()函数通常用于指定字段的元数据,例如默认值和帮助文档。
总之,@dataclass 能够简化类的定义过程,减少重复的代码,提高代码的可读性和可维护性。在上述代码中, @dataclass 装饰器和 field 函数的使用可以使 ModelArguments 和 DataTrainingArguments 类拥有自动生成的初始化方法、表示方法和 getter/setter 方法,并且提供了一些元数据,方便后续使用这些类的对象。
Seq2SeqTrainingArguments(
_n_gpu=0,
adafactor=False,
adam_beta1=0.9,
adam_beta2=0.999,
adam_epsilon=1e-08,
auto_find_batch_size=False,
bf16=False,
bf16_full_eval=False,
data_seed=None,
dataloader_drop_last=False,
dataloader_num_workers=0,
dataloader_pin_memory=True,
ddp_backend=None,
ddp_bucket_cap_mb=None,
ddp_find_unused_parameters=None,
ddp_timeout=1800,
debug=[],
deepspeed=None,
disable_tqdm=False,
do_eval=False,
do_predict=False,
do_train=True,
eval_accumulation_steps=None,
eval_delay=0,
eval_steps=None,
evaluation_strategy=no,
fp16=False,
fp16_backend=auto,
fp16_full_eval=False,
fp16_opt_level=O1,
fsdp=[],
fsdp_config={
'fsdp_min_num_params': 0, 'xla': False, 'xla_fsdp_grad_ckpt': False},
fsdp_min_num_params=0,
fsdp_transformer_layer_cls_to_wrap=None,
full_determinism=False,
generation_config=None,
generation_max_length=None,
generation_num_beams=None,
gradient_accumulation_steps=16,
gradient_checkpointing=False,
greater_is_better=None,
group_by_length=False,
half_precision_backend=auto,
hub_model_id=None,
hub_private_repo=False,
hub_strategy=every_save,
hub_token=<HUB_TOKEN>,
ignore_data_skip=False,
include_inputs_for_metrics=False,
jit_mode_eval=False,
label_names=None,
label_smoothing_factor=0.0,
learning_rate=0.02,
length_column_name=length,
load_best_model_at_end=False,
local_rank=0,
log_level=passive,
log_level_replica=warning,
log_on_each_node=True,
logging_dir=output/adgen-chatglm-6b-pt-$PRE_SEQ_LEN-$LR\runs\Jul25_14-10-13_Jett,
logging_first_step=False,
logging_nan_inf_filter=True,
logging_steps=10,
logging_strategy=steps,
lr_scheduler_type=linear,
max_grad_norm=1.0,
max_steps=3000