编辑
2025-03-27
深度学习
00

目录

基本介绍
自有数据
训练流程架构
关键实现片段
制作训练数据
Docker环境
开始训练
多机多卡

VLM-R1GRPO微调, 实战训练教程(1):

https://www.dong-blog.fun/post/1961

本博客这次使用多图进行GRPO。

官方git项目:https://github.com/om-ai-lab/VLM-R1?tab=readme-ov-file

基本介绍

此项目更新了,支持更多功能。

git clone此项目:

git config --global http.proxy "http://127.0.0.1:10828" git config --global https.proxy "http://127.0.0.1:10828" git clone https://github.com/om-ai-lab/VLM-R1.git --depth=1

This repository supports:

  • Full Fine-tuning for GRPO: see run_grpo_rec.sh
  • Freeze Vision Modules: set freeze_vision_modules as true in the script.
  • LoRA Fine-tuning for GRPO: see run_grpo_rec_lora.sh
  • Multi-node Training: see multinode_training_demo.sh
  • Multi-image Input Training: see run_grpo_gui.sh
  • For your own data: see here
  • Support various VLMs: see How to add a new model, now we support QwenVL and InternVL

自有数据

单图:

json
{ "id": 1, "image": "Clevr_CoGenT_TrainA_R1/data/images/CLEVR_trainA_000001_16885.png", "conversations": [ {"from": "human", "value": "<image>What number of purple metallic balls are there?"}, {"from": "gpt", "value": "0"} ] }

多图:

json
{ "id": 1, "image": ["Clevr_CoGenT_TrainA_R1/data/images/CLEVR_trainA_000001_16885.png", "Clevr_CoGenT_TrainA_R1/data/images/CLEVR_trainA_000001_16886.png"], "conversations": [ {"from": "human", "value": "<image><image>What number of purple metallic balls in total within the two images?"}, {"from": "gpt", "value": "3"} ] }
  1. 数据加载部分已经支持多图:
python:e:\workcode\vlm-r1\VLM-R1\src\open-r1-multimodal\src\open_r1\grpo_jsonl.py
# ... existing code ... if isinstance(item['image'], list): # if the image is a list, then it is a list of images (for multi-image input) item['image_path'] = [os.path.join(image_folder, image) for image in item['image']] del item['image'] # remove the image column so that it can be loaded later # ... existing code ...
  1. 对话构建部分也支持多图:
python:e:\workcode\vlm-r1\VLM-R1\src\open-r1-multimodal\src\open_r1\grpo_jsonl.py
# ... existing code ... 'prompt': [{ 'role': 'user', 'content': [ *({'type': 'image', 'text': None} for _ in range(len(example['image_path']))), {'type': 'text', 'text': question_prompt.format(Question=example['problem'])} ] }] # ... existing code ...

训练流程架构

python
VLMGRPOTrainer ├── 初始化阶段 │ ├── 加载基础模型 (支持LoRA和PEFT) │ ├── 冻结视觉模块 (根据配置) │ ├── 创建参考模型 (用于KL散度计算) │ ├── 加载奖励模型集合 (支持多奖励函数融合) │ └── 配置生成参数 (max_completion_length/temperature等) │ ├── 训练步骤 │ ├── 生成阶段 │ │ ├── 使用基础模型生成候选响应 (num_generations次/样本) │ │ └── 使用vLLM加速生成 (可选) │ │ │ ├── 奖励计算 │ │ ├── 调用所有奖励函数计算综合得分 │ │ └── 应用reward_weights加权 │ │ │ ├── 策略优化 │ │ ├── 计算策略梯度 (带epsilon裁剪) │ │ ├── 多步迭代优化 (num_iterations次/批) │ │ └── 同步参考模型 (TR-DPO策略) │ │ │ └── 日志记录 │ ├── 记录(prompt, completion)样本 │ └── 监控KL散度/奖励值等指标 │ └── 特殊处理 ├── DeepSpeed ZeRO-3支持 ├── 梯度检查点优化 └── 多GPU分布式训练

关键实现片段

python:e:\workcode\vlm-r1\VLM-R1\src\open-r1-multimodal\src\open_r1\trainer\grpo_trainer.py
# 生成阶段核心逻辑(简化) def training_step(self, model, inputs): # 多步迭代优化 for _ in range(self.num_iterations): # 生成候选响应 with torch.no_grad(): outputs = model.generate( inputs, generation_config=self.generation_config, num_return_sequences=self.num_generations ) # 计算奖励值 rewards = [] for reward_func in self.reward_funcs: if isinstance(reward_func, PreTrainedModel): reward_values = reward_func(outputs).logits else: # 自定义奖励函数 reward_values = reward_func(inputs["prompt"], outputs) rewards.append(reward_values) total_reward = torch.stack(rewards).sum(0) # 策略梯度计算 policy_logits = model(outputs, labels=outputs).logits ref_logits = self.ref_model(outputs, labels=outputs).logits # 带裁剪的梯度更新 ratio = (policy_logits - ref_logits).exp() clipped_ratio = torch.clamp(ratio, 1-self.epsilon, 1+self.epsilon) loss = -torch.min(ratio * total_reward, clipped_ratio * total_reward).mean() # 梯度累积 loss = loss / self.args.gradient_accumulation_steps self.accelerator.backward(loss) # TR-DPO模型同步 if self.global_step % self.ref_model_sync_steps == 0: self._sync_ref_model() # 参考模型同步逻辑 def _sync_ref_model(self): # 指数移动平均更新 alpha = self.args.ref_model_mixup_alpha for param, ref_param in zip(self.model.parameters(), self.ref_model.parameters()): ref_param.data = alpha * param.data + (1 - alpha) * ref_param.data

制作训练数据

x05生成训练数据集代码.py

python
import os import json from pathlib import Path def generate_jsonl_dataset(): # 1. 读取prompt2.txt里的文件内容 with open('prompt2.txt', 'r', encoding='utf-8') as f: prefix_str = f.read().strip() # 基础路径 base_path = "/data/xiedong/VLM-train-project/tasks-json-ui-doctor" # 输出文件 output_file = "ui_doctor_dataset.jsonl" # 获取所有子目录并按数字排序 subdirs = [d for d in os.listdir(base_path) if os.path.isdir(os.path.join(base_path, d))] # 过滤出纯数字的子目录并按数字大小排序 numeric_subdirs = sorted( [d for d in subdirs if d.isdigit()], key=lambda x: int(x) ) sample_id = 1 with open(output_file, 'w', encoding='utf-8') as out_f: # 遍历每个子目录(已排序) for dir_name in numeric_subdirs: dir_path = os.path.join(base_path, dir_name) # 获取当前目录下的所有step_*.json文件并按数字排序 json_files = sorted( [f for f in os.listdir(dir_path) if f.startswith('step_') and f.endswith('.json')], key=lambda x: int(x.split('_')[1].split('.')[0]) ) # 遍历排序后的json文件 for file_name in json_files: json_path = os.path.join(dir_path, file_name) # 读取json文件 with open(json_path, 'r', encoding='utf-8') as json_f: data = json.load(json_f) # 处理input和output字段 input_data = data['input'] output_data = data['output'] # 收集图片路径 image_paths = [] # 处理screen_path1 if 'screen_path1' in input_data and input_data['screen_path1']: img_path = os.path.join(dir_name, input_data['screen_path1']) image_paths.append(img_path) # 处理screen_path2 if 'screen_path2' in input_data and input_data['screen_path2']: img_path = os.path.join(dir_name, input_data['screen_path2']) image_paths.append(img_path) # 构建conversations conversations = [ { "from": "human", "value": prefix_str + json.dumps(input_data, ensure_ascii=False) }, { "from": "gpt", "value": json.dumps(output_data, ensure_ascii=False) } ] # 构建最终样本 sample = { "id": sample_id, "image": image_paths, "conversations": conversations } # 写入jsonl文件 out_f.write(json.dumps(sample, ensure_ascii=False) + '\n') sample_id += 1 print(f"数据集已生成,共{sample_id-1}个样本,保存到{output_file}") if __name__ == "__main__": generate_jsonl_dataset()

一个json是这个样子:

json
================================================== 完整的JSON结构: ================================================== { "id": 1, "image": [ "43688/43688_2.jpg", "43688/43688_3.jpg" ], "conversations": [ { "from": "human", "value": "# Role: 手机任务执行专家\n\n## Profile\n- author: LangGPT\n- version: 1.0\n- language: 中英文\n- description: 你是一个手机任务执行专家,可以根据UI图和任务提示,输出具体的操作动作\n\n## Skills\n- 根据UI图识别出当前所在UI界面的信息\n- 为了完成任务,需要输出具体动作\n- 分析任务描述,提供精确的执行步骤\n- 精通不同类型的动作空间,并能生成相应的操作指令\n\n## Background\n在手机任务执行中,AI需要根据任务描述、UI图以及历史操作,确定精确的动作,并给出相应的操作参数。\n下面这个json是一个输入示例:\n{\n \"task_content\": \"在书架中找到剑来,前往内容页,使用章节下载功能,先选择第5章,第7章,再选择第10章进行下载。\",\n \"task_path\": {\n \"1\": \"打开APP\",\n \"2\": \"点击剑来\",\n \"3\": \"点击小说界面\",\n \"4\": \"点击订阅\",\n \"5\": \"点击继续订阅\",\n \"6\": \"等待\",\n \"7\": \"点击自定义\",\n \"8\": \"点击第5章 道破\",\n \"9\": \"点击第7章 碗水\",\n \"10\": \"等待\",\n \"11\": \"点击第10章 食牛之气\",\n \"12\": \"点击下载\",\n \"13\": \"等待\",\n \"14\": \"等待\"\n },\n \"screen_path1\": \"9953_0.jpg\",\n \"screen_path2\": \"9953_1.jpg\",\n \"history_path_all\": [\n \"打开APP\"\n ],\n \"app_name\": \"起点读书\",\n \"action_type_list\": {\n \"open_app\": \"打开APP\",\n \"click\": \"点击\",\n \"long_click\": \"长按\",\n \"type\": \"输入\",\n \"swipe\": \"滑动\",\n \"task_completed\": \"任务完成\",\n \"task_impossible\": \"任务无法完成\",\n \"inquiry\": \"反问\",\n \"wait\": \"等待\",\n \"back\": \"回退\"\n }\n}\n输入的json中的字段的含义是:\n- task_content 当前任务的总体描述\n- task_path 当前任务所需要的执行步骤\n- screen_path1 上次步骤中的手机UI图,真实情况下这是一张图而不是路径名\n- screen_path2 这次步骤中的手机UI图,真实情况下这是一张图而不是路径名\n- history_path_all 之前执行过的执行步骤\n- app_name 当前操作的APP名称\n- action_type_list 允许的动作空间的类型\n\n\n\n## 动作空间\n\n你的输出是此时应该进行的执行步骤,使用动作空间里的动作表达,下面是动作空间的所有允许操作:\n\n- open_app 打开APP,这代表打开微信:\n\"action_parameter\": {\n \"open_app\": \"微信\"\n}\n\n- click 点击区域对应边界框,这代表点击这个框\"37,378,227,633\"里面的区域:\n\"action_parameter\": {\n \"click\": \"37,378,227,633\"\n}\n\n- long_click 长按区域对应边界框,这代表长按这个框\"763,2183,1151,2706\"里面的区域:\n\"action_parameter\": {\n \"long_click\": \"763,2183,1151,2706\"\n}\n\n- type 输入内容,这代表输入\"无锡\"\n\"action_parameter\": {\n \"type\": \"无锡\"\n}\n\n• swipe 滑动区域,这代表从坐标\"158,1557\"滑动到\"122,1253\":\n\"action_parameter\": {\n \"swipe\": \"158,1557,122,1253\"\n}\n\n• task_completed 任务完成,这代表任务已完成并返回描述信息:\n\"action_parameter\": {\n \"task_completed\": \"任务已完成,已在视频号中搜索并浏览了与无锡相关的视频。视频内容介绍了无锡的城市风貌和地标建筑。\"\n}\n\n• inquiry 反问,这代表返回反问内容和候选列表:\n\"action_parameter\": {\n \"inquiry\": \"{\\n \\\"Question\\\": \\\"搜索笑脸后有多个表情包,请问您想发送哪一个?\\\",\\n \\\"CandidatesList\\\": \\\"['黄色大笑脸', '手绘风格笑脸', '红晕笑脸', '黄色微笑脸', '小笑脸', '手指笑脸', '捂脸笑脸', '狗狗笑脸', '向日葵笑脸', '简单线条笑脸', '气到变形笑脸', '太阳笑脸', '躺着的笑脸', '狡黠笑脸']\\\",\\n \\\"PicDescribe\\\": \\\"聊天界面中显示了表情搜索结果,包含多个笑脸表情包。\\\",\\n \\\"AnswerIndex\\\": 0\\n}\"\n}\n\n• wait 等待,这代表等待:\n\"action_parameter\": {\n \"wait\": \"\"\n}\n\n• back 回退,这代表回退:\n\"action_parameter\": {\n \"back\": \"\"\n}\n\n## Goals\n根据任务描述、UI图和历史执行步骤,生成准确的手机操作动作。\n\n## OutputFormat\n{\n \"action_type\": \"{动作类型}\",\n \"action_parameter\": {动作参数},\n \"action_description\": \"{动作描述}\"\n}\n这是一个输出例子,输出的json需要有字段action_type、action_parameter、action_description\n{\n \"action_type\": \"click\",\n \"action_parameter\": {\n \"click\": \"49,721,1368,1008\"\n },\n \"action_description\": \"点击剑来\"\n}\n\n## Rules\n1. 根据输入的任务内容和UI图,生成合适的手机操作。\n2. 动作类型和参数需要与实际手机操作的UI区域对应。\n3. 输出需要是json字符串,而且是有效的动作表达。\n\n## Workflows\n1. 收集并分析任务描述、UI图及历史步骤。\n2. 根据UI图识别当前步骤的具体位置和操作类型。\n3. 生成与任务相关的动作空间,并匹配合适的动作。\n4. 输出符合要求的手机操作动作,需要是json字符串表达格式。\n\n## 开始任务\n\n请根据以下的任务描述、UI图以及历史操作,确定精确的动作,输出相应的操作参数:{\"task_content\": \"打开淘宝 app。点击屏幕底部的 '购物车' 图标。浏览购物车中的商品,找到你喜欢的商品并点击进入商品详情页。点击商品店铺中的 '关注' 按钮。\", \"task_path\": {\"1\": \"打开APP\", \"2\": \"点击底部购物车\", \"3\": \"点击商品金丝楠木书签定制高端送礼\", \"4\": \"等待\", \"5\": \"点击店铺\", \"6\": \"点击关注\", \"7\": \"点击X按钮\", \"8\": \"点击UIAgent标注辅助工具\"}, \"screen_path1\": \"<image>\", \"screen_path2\": \"<image>\", \"history_path_all\": [\"打开APP\", \"点击底部购物车\", \"点击商品金丝楠木书签定制高端送礼\"], \"app_name\": \"淘宝\", \"action_type_list\": {\"open_app\": \"打开APP\", \"click\": \"点击\", \"long_click\": \"长按\", \"type\": \"输入\", \"swipe\": \"滑动\", \"task_completed\": \"任务完成\", \"task_impossible\": \"任务无法完成\", \"inquiry\": \"反问\", \"wait\": \"等待\", \"back\": \"回退\"}}" }, { "from": "gpt", "value": "{\"action_type\": \"wait\", \"action_parameter\": {\"wait\": \"\"}, \"action_description\": \"等待\"}" } ] } ================================================== 解析conversations中的value字段: ================================================== 对话 1 (human): ---------------------------------------- (原始字符串内容): # Role: 手机任务执行专家 ## Profile - author: LangGPT - version: 1.0 - language: 中英文 - description: 你是一个手机任务执行专家,可以根据UI图和任务提示,输出具体的操作动作 ## Skills - 根据UI图识别出当前所在UI界面的信息 - 为了完成任务,需要输出具体动作 - 分析任务描述,提供精确的执行步骤 - 精通不同类型的动作空间,并能生成相应的操作指令 ## Background 在手机任务执行中,AI需要根据任务描述、UI图以及历史操作,确定精确的动作,并给出相应的操作参数。 下面这个json是一个输入示例: { "task_content": "在书架中找到剑来,前往内容页,使用章节下载功能,先选择第5章,第7章,再选择第10章进行下载。", "task_path": { "1": "打开APP", "2": "点击剑来", "3": "点击小说界面", "4": "点击订阅", "5": "点击继续订阅", "6": "等待", "7": "点击自定义", "8": "点击第5章 道破", "9": "点击第7章 碗水", "10": "等待", "11": "点击第10章 食牛之气", "12": "点击下载", "13": "等待", "14": "等待" }, "screen_path1": "9953_0.jpg", "screen_path2": "9953_1.jpg", "history_path_all": [ "打开APP" ], "app_name": "起点读书", "action_type_list": { "open_app": "打开APP", "click": "点击", "long_click": "长按", "type": "输入", "swipe": "滑动", "task_completed": "任务完成", "task_impossible": "任务无法完成", "inquiry": "反问", "wait": "等待", "back": "回退" } } 输入的json中的字段的含义是: - task_content 当前任务的总体描述 - task_path 当前任务所需要的执行步骤 - screen_path1 上次步骤中的手机UI图,真实情况下这是一张图而不是路径名 - screen_path2 这次步骤中的手机UI图,真实情况下这是一张图而不是路径名 - history_path_all 之前执行过的执行步骤 - app_name 当前操作的APP名称 - action_type_list 允许的动作空间的类型 ## 动作空间 你的输出是此时应该进行的执行步骤,使用动作空间里的动作表达,下面是动作空间的所有允许操作: - open_app 打开APP,这代表打开微信: "action_parameter": { "open_app": "微信" } - click 点击区域对应边界框,这代表点击这个框"37,378,227,633"里面的区域: "action_parameter": { "click": "37,378,227,633" } - long_click 长按区域对应边界框,这代表长按这个框"763,2183,1151,2706"里面的区域: "action_parameter": { "long_click": "763,2183,1151,2706" } - type 输入内容,这代表输入"无锡" "action_parameter": { "type": "无锡" } • swipe 滑动区域,这代表从坐标"158,1557"滑动到"122,1253""action_parameter": { "swipe": "158,1557,122,1253" } • task_completed 任务完成,这代表任务已完成并返回描述信息: "action_parameter": { "task_completed": "任务已完成,已在视频号中搜索并浏览了与无锡相关的视频。视频内容介绍了无锡的城市风貌和地标建筑。" } • inquiry 反问,这代表返回反问内容和候选列表: "action_parameter": { "inquiry": "{\n \"Question\": \"搜索笑脸后有多个表情包,请问您想发送哪一个?\",\n \"CandidatesList\": \"['黄色大笑脸', '手绘风格笑脸', '红晕笑脸', '黄色微笑脸', '小笑脸', '手指笑脸', '捂脸笑脸', '狗狗笑脸', '向日葵笑脸', '简单线条笑脸', '气到变形笑脸', '太阳笑脸', '躺着的笑脸', '狡黠笑脸']\",\n \"PicDescribe\": \"聊天界面中显示了表情搜索结果,包含多个笑脸表情包。\",\n \"AnswerIndex\": 0\n}" } • wait 等待,这代表等待: "action_parameter": { "wait": "" } • back 回退,这代表回退: "action_parameter": { "back": "" } ## Goals 根据任务描述、UI图和历史执行步骤,生成准确的手机操作动作。 ## OutputFormat { "action_type": "{动作类型}", "action_parameter": {动作参数}, "action_description": "{动作描述}" } 这是一个输出例子,输出的json需要有字段action_type、action_parameter、action_description { "action_type": "click", "action_parameter": { "click": "49,721,1368,1008" }, "action_description": "点击剑来" } ## Rules 1. 根据输入的任务内容和UI图,生成合适的手机操作。 2. 动作类型和参数需要与实际手机操作的UI区域对应。 3. 输出需要是json字符串,而且是有效的动作表达。 ## Workflows 1. 收集并分析任务描述、UI图及历史步骤。 2. 根据UI图识别当前步骤的具体位置和操作类型。 3. 生成与任务相关的动作空间,并匹配合适的动作。 4. 输出符合要求的手机操作动作,需要是json字符串表达格式。 ## 开始任务 请根据以下的任务描述、UI图以及历史操作,确定精确的动作,输出相应的操作参数: {"task_content": "打开淘宝 app。点击屏幕底部的 '购物车' 图标。浏览购物车中的商品,找到你喜欢的商品并点击进入商品详情页。点击商品店铺中的 '关注' 按钮。", "task_path": {"1": "打开APP", "2": "点击底部购物车", "3": "点击商品金丝楠木书签定制高端送礼", "4": "等待", "5": "点击店铺", "6": "点击关注", "7": "点击X按钮", "8": "点击UIAgent标注辅助工具"}, "screen_path1": "<image>", "screen_path2": "<image>", "history_path_all": ["打开APP", "点击底部购物车", "点击商品金丝楠木书签定制高端送礼"], "app_name": "淘宝", "action_type_list": {"open_app": "打开APP", "click": "点击", "long_click": "长按", "type": "输入", "swipe": "滑动", "task_completed": "任务完成", "task_impossible": "任务无法完成", "inquiry": "反问", "wait": "等待", "back": "回退"}} 对话 2 (gpt): ---------------------------------------- (JSON格式内容):docker run -it --gpus '"device=1,2,3"' \ --shm-size=64g \ -v ./tasks-json-ui-doctor:/tasks-json-ui-doctor \ -v ./ui_doctor_dataset.jsonl:/datasets/ui_doctor_dataset.jsonl \ -v ./VLM-R1:/VLM-R1 \ --net host \ kevinchina/deeplearning:2.5.1-cuda12.4-cudnn9-devel-vlmr1 bash { "action_type": "wait", "action_parameter": { "wait": "" }, "action_description": "等待" }

Docker环境

bash
docker build -f Dockerfile -t kevinchina/deeplearning:2.5.1-cuda12.4-cudnn9-devel-vlmr1-0401 . 或者: docker build --network=host --build-arg http_proxy=http://101.136.19.26:10828 --build-arg https_proxy=http://101.136.19.26:10828 -f Dockerfile -t kevinchina/deeplearning:2.5.1-cuda12.4-cudnn9-devel-vlmr1-0401 .

安装一些包:

pip install babel python-Levenshtein matplotlib pycocotools
bash
docker commit 810854b5d4b4 kevinchina/deeplearning:2.5.1-cuda12.4-cudnn9-devel-vlmr1-0401-package

开始训练

启动容器:

bash
cd /data/xiedong/VLM-train-project docker run -it --gpus '"device=1,2,3,4,5"' \ --shm-size=64g \ -v ./tasks-json-ui-doctor:/tasks-json-ui-doctor \ -v ./ui_doctor_dataset.jsonl:/datasets/ui_doctor_dataset.jsonl \ -v ./Qwen2.5-VL-7B-Instruct:/Qwen2.5-VL-7B-Instruct \ --net host \ kevinchina/deeplearning:2.5.1-cuda12.4-cudnn9-devel-vlmr1-0401-package-rdma bash

在容器中编辑启动脚本:

bash
cd /workspace vim src/open-r1-multimodal/run_scripts/run_grpo_gui.sh

修改 --nproc_per_node 指定显卡,

修改 --model_name_or_path 指定模型文件,

修改 --image_folders 指定图片路径前缀,

修改 --data_file_paths 指定训练数据,

修改 --max_prompt_length 模型生成的最大长度,

修改 --num_train_epochs 指定训练轮数,

修改 --per_device_train_batch_size 指定batch。

-- num_generations 表示对每个提示(prompt)生成的不同回复数量,全局批次大小(num_processes * per_device_batch_size)必须能被这个值整除

最终我的:

bash
cd src/open-r1-multimodal export DEBUG_MODE="true" # export CUDA_VISIBLE_DEVICES=4,5,6,7 RUN_NAME="Qwen2.5-VL-3B-GRPO-GUI_multi-image" export LOG_PATH="./debug_log_$RUN_NAME.txt" torchrun --nproc_per_node="5" \ --nnodes="1" \ --node_rank="0" \ --master_addr="127.0.0.1" \ --master_port="22346" \ src/open_r1/grpo_jsonl.py \ --deepspeed local_scripts/zero3.json \ --output_dir output/$RUN_NAME \ --model_name_or_path /Qwen2.5-VL-7B-Instruct \ --dataset_name none \ --image_folders /tasks-json-ui-doctor \ --data_file_paths /datasets/ui_doctor_dataset.jsonl \ --freeze_vision_modules true \ --max_prompt_length 4096 \ --num_generations 5 \ --per_device_train_batch_size 1 \ --gradient_accumulation_steps 1 \ --logging_steps 1 \ --bf16 \ --torch_dtype bfloat16 \ --data_seed 42 \ --report_to none \ --gradient_checkpointing true \ --attn_implementation flash_attention_2 \ --num_train_epochs 1 \ --run_name $RUN_NAME \ --save_steps 100 \ --save_only_model true

运行训练:

bash
bash src/open-r1-multimodal/run_scripts/run_grpo_gui.sh

训练日志:

{'loss': 0.0, 'grad_norm': 7.915220396365858, 'learning_rate': 9.99982068141064e-07, 'completion_length': 138.40000915527344, 'rewards/accuracy_reward': 0.7174350023269653, 'rewards/format_reward': 1.0, 'reward': 1.7174350023269653, 'reward_std': 0.0657886490225792, 'kl': 0.0004730224609375, 'clip_ratio': 0.0, 'epoch': 0.0} 0%| | 3/167300 [00:57<871:05:01, 18.74s/it]

多机多卡

要执行一下命令,安装libibverbs1才能使用rdma网卡,加速训练

sudo apt-get update sudo apt-get install libibverbs1 -y
docker commit a04ef2131657 kevinchina/deeplearning:2.5.1-cuda12.4-cudnn9-devel-vlmr1-0401-package-rdma

数据集挂载到 /tasks-json-ui-doctor

子目录:tasks_json/

子目录:ui_doctor_dataset.jsonl

bash
cd src/open-r1-multimodal export DEBUG_MODE="true" RUN_NAME="Qwen2.5-VL-7B-GRPO-GUI_multi-image" export LOG_PATH="./debug_log_$RUN_NAME.txt" torchrun --nproc_per_node=8 \ --nnodes=2 \ --node_rank=${RANK} \ --master_addr=${MASTER_ADDR} \ --master_port=${MASTER_PORT} \ src/open_r1/grpo_jsonl.py \ --deepspeed local_scripts/zero3.json \ --output_dir /output_qwen25vl7b_xd/$RUN_NAME \ --model_name_or_path /Qwen2.5-VL-7B-Instruct \ --dataset_name none \ --image_folders /tasks-json-ui-doctor/tasks_json \ --data_file_paths /tasks-json-ui-doctor/ui_doctor_dataset.jsonl \ --freeze_vision_modules true \ --max_prompt_length 4096 \ --num_generations 8 \ --per_device_train_batch_size 1 \ --gradient_accumulation_steps 1 \ --logging_steps 1 \ --bf16 \ --torch_dtype bfloat16 \ --data_seed 42 \ --report_to "tensorboard" \ --logging_dir "/mnt/clusterds123412sfdasd" --gradient_checkpointing true \ --attn_implementation flash_attention_2 \ --num_train_epochs 2 \ --run_name $RUN_NAME \ --save_steps 100 \ --save_only_model true

环境变量:

CUDA_DEVICE_MAX_CONNECTIONS 1

NCCL_DEBUG INFO

NCCL_IB_DISABLE 0

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Dong

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!