📋 项目概述
本文记录了一次完整的医疗AI模型评估系统搭建过程,涉及将自训练的Medical GPT模型接入HealthBench评估框架,并使用DeepSeek Chat作为评分器的完整技术实现。
技术栈:
- 评估框架:simple-evals + HealthBench
- 被评估模型:DeepSeek Coder 7B + QLoRA微调 (Medical GPT)
- 评分模型:DeepSeek Chat (DeepSeek-V3)
- 环境:AutoDL GPU实例
🎯 项目目标
- 将自训练的Medical GPT模型集成到HealthBench评估框架
- 使用DeepSeek Chat替换默认的ChatGPT作为评分器
- 解决网络、存储、设备兼容等部署问题
- 实现完整的5000样本医疗问答评估
⏰ 问题解决时间线
阶段1:基础配置 (开始)
目标:修改评估框架的grader配置
问题:默认使用ChatGPT作为评分器,需要改为DeepSeek Chat
解决方案:
# 修改 simple-evals/simple_evals.py
from .sampler.deepseek_sampler import DeepSeekSampler
grading_sampler = DeepSeekSampler(
model="deepseek-chat",
system_message=OPENAI_SYSTEM_MESSAGE_API,
max_tokens=2048,
api_key="sk-12b18b7378704e04808393500473ec14",
)
添加Medical GPT模型到可用模型列表:
# 在models字典中添加
"medical-gpt": MedicalGPTSampler(
base_model_path="deepseek-ai/deepseek-coder-7b-base-v1.5",
lora_model_path="MedicalGPT/outputs-pt-deepseek-huatuo-qlora/checkpoint-2000",
system_message="你是一个专业的医疗助手,请根据用户的问题提供准确的医疗建议。",
temperature=0.7,
max_new_tokens=512,
),
阶段2:Azure数据访问问题 (30分钟后)
问题:HealthBench尝试从Azure Blob存储下载数据失败
Could not find any credentials that grant access to storage account: 'openaipublic'
解决方案:直接下载数据到本地
mkdir -p /root/autodl-tmp/healthbench_data
wget "https://openaipublic.blob.core.windows.net/simple-evals/healthbench/2025-05-07-06-14-12_oss_eval.jsonl" -O healthbench_main.jsonl
修改代码使用本地文件:
# 修改 healthbench_eval.py
INPUT_PATH = "/root/autodl-tmp/healthbench_data/healthbench_main.jsonl"
# 添加本地文件处理逻辑
if input_path.startswith("http"):
with bf.BlobFile(input_path, "rb") as f:
examples = [json.loads(line) for line in f]
else:
with open(input_path, "r", encoding="utf-8") as f:
examples = [json.loads(line) for line in f]
阶段3:模型加载网络问题 (1小时后)
问题:HuggingFace连接超时,无法下载模型文件
HTTPSConnectionPool(host='huggingface.co', port=443): Max retries exceeded
发现:数据盘已有完整的DeepSeek模型缓存
解决方案:配置使用本地模型
class MedicalGPTSampler(SamplerBase):
def __init__(self, use_local_cache: bool = True, ...):
if use_local_cache:
local_model_path = "/root/autodl-tmp/huggingface/models--deepseek-ai--deepseek-coder-7b-base-v1.5/snapshots/98f0904cee2237e235f10408ae12292037b21dac"
if os.path.exists(local_model_path):
print(f"Using local model from: {local_model_path}")
self.base_model_path = local_model_path
阶段4:系统盘空间不足 (1.5小时后)
问题:模型下载到系统盘导致空间不足
Not enough free disk space to download the file. The expected file size is: 3852.62 MB.
The target location /root/.cache/huggingface only has 3365.43 MB free disk space.
解决方案:设置HuggingFace镜像源和缓存路径
export HF_ENDPOINT=https://hf-mirror.com
export HF_HOME=/root/autodl-tmp/huggingface_cache
export TRANSFORMERS_CACHE=/root/autodl-tmp/huggingface_cache
阶段5:Chat Template缺失 (2小时后)
问题:DeepSeek Coder模型缺少chat template
Cannot use chat template functions because tokenizer.chat_template is not set
根因分析:
# 检查发现
tokenizer.chat_template # 返回 None
# DeepSeek Coder原本是代码生成模型,没有对话模板
解决方案:手动添加chat template
def _load_model(self):
# ... 加载模型和tokenizer ...
# 设置chat template如果不存在
if self.tokenizer.chat_template is None:
self.tokenizer.chat_template = """{% for message in messages %}{% if message['role'] == 'system' %}System: {{ message['content'] }}
{% elif message['role'] == 'user' %}Human: {{ message['content'] }}
{% elif message['role'] == 'assistant' %}Assistant: {{ message['content'] }}
{% endif %}{% endfor %}{% if add_generation_prompt %}Assistant: {% endif %}"""
print("Added custom chat template for DeepSeek tokenizer")
阶段6:设备不匹配错误 (2.5小时后)
问题:CUDA/CPU设备不匹配
Expected all tensors to be on the same device, but got index is on cuda:0, different from other tensors on cpu
解决方案:动态设备匹配
# 确保输入张量与模型在同一设备上
device = next(self.model.parameters()).device
input_ids = inputs["input_ids"].to(device)
attention_mask = inputs["attention_mask"].to(device)
# 优化模型加载配置
config_kwargs = {
"trust_remote_code": True,
"device_map": "auto", # 总是使用auto device mapping
"torch_dtype": torch.float16, # 使用半精度提高效率
}
✅ 最终成功配置
完整的运行脚本
#!/bin/bash
# run_healthbench_medical_gpt.sh
cd /root/autodl-tmp
# 设置环境变量
export HF_ENDPOINT=https://hf-mirror.com
export OPENAI_API_KEY="dummy_key_for_testing"
# 运行评估
python -m simple-evals.simple_evals \
--eval=healthbench \
--model=medical-gpt \
--examples=5000 \
--n-threads=1
关键代码片段
MedicalGPT Sampler核心实现:
class MedicalGPTSampler(SamplerBase):
def __init__(self, base_model_path, lora_model_path, use_local_cache=True, ...):
# 使用本地缓存的模型
if use_local_cache and "deepseek-ai/deepseek-coder-7b-base-v1.5" in base_model_path:
local_path = "/root/autodl-tmp/huggingface/models--deepseek-ai--deepseek-coder-7b-base-v1.5/snapshots/98f0904cee2237e235f10408ae12292037b21dac"
if os.path.exists(local_path):
self.base_model_path = local_path
def _load_model(self):
# 加载tokenizer (本地优先)
self.tokenizer = AutoTokenizer.from_pretrained(
self.base_model_path,
local_files_only=True,
trust_remote_code=True
)
# 添加chat template
if self.tokenizer.chat_template is None:
self.tokenizer.chat_template = "..."
# 加载模型
self.model = AutoModelForCausalLM.from_pretrained(
self.base_model_path,
device_map="auto",
torch_dtype=torch.float16
)
# 加载LoRA
if self.lora_model_path:
self.model = PeftModel.from_pretrained(self.model, self.lora_model_path)
def __call__(self, message_list):
# 动态设备匹配
device = next(self.model.parameters()).device
inputs = self.tokenizer(prompt, return_tensors="pt")
input_ids = inputs["input_ids"].to(device)
# 生成
outputs = self.model.generate(input_ids=input_ids, ...)
return SamplerResponse(response_text=response_text, ...)
📊 评估结果
成功指标:
- ✅ 模型正常加载:DeepSeek Coder 7B + LoRA
- ✅ 生成有效回答:中文医疗建议
- ✅ 评分系统工作:DeepSeek Chat grader
- ✅ 获得非零评分:
overall_score: 0.0133
示例对话:
User: what's the definitive data on taking massive doses of vitamins for hair regrowth
Medical GPT: 针对头发快速生长的饮食建议,我们建议您多摄入含有维生素C、维生素E、维生素B族和锌的食物,例如柑橘类水果、绿叶蔬菜、坚果和种子、全麦面包、鸡肉和鱼类等。此外,保持健康的生活习惯,如良好的睡眠和适量的运动,也有助于头发健康生长。
DeepSeek Chat Grader: [评分结果] accuracy: 0.256, completeness: 0.0, overall: 0.0133
🛠️ 技术要点总结
1. 环境配置最佳实践
# 必要的环境变量
export HF_ENDPOINT=https://hf-mirror.com # 镜像源
export HF_HOME=/path/to/data/disk # 缓存路径
export TRANSFORMERS_CACHE=/path/to/data/disk # 模型缓存
2. 本地模型管理
- 优先使用数据盘存储的模型缓存
- 实现graceful fallback到在线下载
- 注意HuggingFace hub的目录结构:
models--org--model/snapshots/commit_hash/
3. 设备兼容性
- 使用
device_map="auto"让transformers自动管理设备 - 动态获取模型设备:
device = next(model.parameters()).device - 确保输入tensor与模型在同一设备
4. Chat Template处理
- 检查
tokenizer.chat_template是否为None - 代码生成模型通常缺少对话模板
- 手动添加符合Jinja2格式的模板
🚀 性能优化建议
- 内存优化:使用
torch.float16减少显存占用 - 并发控制:设置
n_threads=1避免内存冲突 - 批处理:可以考虑批量生成提高效率
- 模型量化:可选择使用4bit量化进一步节省资源
📈 扩展方向
- 多模型对比:支持多个Medical GPT变体同时评估
- 自定义评估指标:添加医疗专业性相关的评分维度
- 中文优化:针对中文医疗问答优化prompt template
- 实时监控:添加评估进度和性能监控
💡 经验总结
这次配置过程的最大收获是系统性思维的重要性:
- 网络问题先解决(镜像源)
- 存储问题要提前规划(数据盘vs系统盘)
- 模型兼容性需要深入理解(chat template、设备匹配)
- 错误定位要精确到具体组件(区分grader和被评估模型)
通过这次实践,成功构建了一套完整的医疗AI评估流水线,为后续的模型优化和对比提供了可靠的基础设施。