找回密码
 注册

Sign in with Twitter

It's what's happening?

微信登录

微信扫一扫,快速登录

萍聚头条

查看: 127|回复: 0

AI架构师之路 第17课--构建企业级AI自动化训练与部署流水线(Fine-tune + Eval + Serve)

[复制链接]
发表于 2025-11-11 14:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册 微信登录

×
作者:微信文章
一、目标

构建一个端到端的 AI 模型交付流水线,实现:
    一键触发微调(Fine-tune)自动评估(Eval)模型效果无缝部署(Serve)为线上服务支持版本管理、回滚、监控与 A/B 测试


二、核心阶段与功能

阶段目标关键任务
1. Fine-tune(微调)在特定领域数据上优化基础模型- 数据预处理
- 分布式训练(DDP/FSDP/DeepSpeed)
- 超参搜索(可选)
- 模型 checkpoint 保存
2. Eval(评估)客观衡量模型性能- 在验证集/测试集上推理
- 计算指标(准确率、F1、BLEU、ROUGE 等)
- 人工评估抽样(可选)
- 生成评估报告
3. Serve(部署)将模型提供为低延迟、高可用服务- 模型格式转换(如 ONNX/TensorRT)
- 推理服务封装(vLLM/TGI/FastAPI)
- 自动扩缩容、健康检查
- API 网关接入


三、典型技术栈



功能推荐工具
编排引擎Airflow, Kubeflow Pipelines, Metaflow, Prefect, GitHub Actions
训练框架Hugging Face Transformers + Accelerate / DeepSpeed / FSDP
评估框架evaluate (HF), torchmetrics, 自定义脚本
模型注册表MLflow Model Registry, Weights & Biases (W&B), DVC
部署方案vLLM, TensorRT-LLM, TGI (Text Generation Inference), FastAPI + Docker
基础设施Kubernetes (K8s), Docker, AWS SageMaker, Azure ML, GCP Vertex AI
监控与日志Prometheus + Grafana, ELK, OpenTelemetry


四、流水线流程示例(以 LLM 微调为例)



w1.jpg

五、关键实践要点




1. 数据与代码版本化

    使用 Git 管理训练脚本使用 DVC 或 Lakehouse 管理数据集版本记录训练超参(如 learning_rate=2e-5)
2. 模型可追溯性

    每次训练生成唯一 run_id关联:代码 commit + 数据版本 + 超参 + 评估结果工具:MLflow / W&B / ClearML
3. 评估驱动部署(Evaluation-Gated Deployment)

    设定阈值(如 Rouge-L ≥ 0.45)未达标则阻断部署流程支持多维度评估(安全性、偏见、业务指标)
4. 部署策略

    蓝绿部署新旧版本并行,切换流量金丝雀发布先对 5% 用户开放回滚机制自动检测异常(如 P99 延迟飙升)并回退
5. 成本与性能平衡

    微调阶段:用 Spot 实例降低成本推理阶段:根据 QPS 动态扩缩容模型压缩:量化(INT4/INT8)+ 蒸馏

六、企业级成熟且完整的自动化训练与部署流水线示例需要支持的功能:
    LoRA 微调 Qwen-7B(使用 Hugging Face + PEFT)MLflow 模型注册 + 自动触发部署GitLab CI/CD 流水线Kubernetes 部署模板(含 vLLM 推理服务)私有化(不依赖公网)

1、整体架构图
w2.jpg
2、项目结构

qwen-lora-pipeline/├── data/│   └── alpaca_zh_demo.json      # 中文指令微调数据(Alpaca 格式)├── src/│   ├── train_lora.py            # LoRA 微调脚本│   ├── evaluate_model.py        # 评估 + 注册到 MLflow│   └── create_k8s_manifest.py   # 动态生成 K8s YAML(可选)├── docker/│   ├── Dockerfile.vllm          # vLLM + LoRA 推理镜像│   └── entrypoint.sh            # 启动脚本├── k8s/│   └── deployment.yaml.tpl      # K8s 模板├── requirements.txt├── .gitlab-ci.yml└── config.yaml                  # 超参配置
3、核心组件实现
requirements.txt

torch==2.1.0transformers>=4.35accelerate>=0.24peft>=0.6datasets>=2.14mlflow>=2.8sentencepieceeinopsvllm>=0.3.0src/train_lora.py(LoRA 微调 Qwen-7B)

import osimport jsonimport mlflowfrom datasets import load_datasetfrom transformers import (    AutoTokenizer,    AutoModelForCausalLM,    TrainingArguments,    Trainer,    DataCollatorForSeq2Seq)from peft import LoraConfig, get_peft_model, TaskTypedef main():    mlflow.set_tracking_uri(os.getenv("MLFLOW_TRACKING_URI", "http://mlflow:5000"))    mlflow.set_experiment("qwen-lora-finetune")    with mlflow.start_run():        model_name = "/models/Qwen-7B-Chat"  # 私有模型路径(预下载)        tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)        model = AutoModelForCausalLM.from_pretrained(            model_name,            trust_remote_code=True,            device_map="auto",            torch_dtype="auto"        )        # 启用 LoRA        peft_config = LoraConfig(            task_type=TaskType.CAUSAL_LM,            inference_mode=False,            r=64,            lora_alpha=16,            lora_dropout=0.1,            target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],        )        model = get_peft_model(model, peft_config)        model.print_trainable_parameters()  # 打印可训练参数量        # 加载数据        dataset = load_dataset("json", data_files="data/alpaca_zh_demo.json")["train"]        def format_example(example):            return f"### Instruction:\n{example['instruction']}\n\n### Input:\n{example['input']}\n\n### Response:\n{example['output']}"        def tokenize_function(examples):            texts = [format_example(ex) for ex in examples["examples"]]            return tokenizer(texts, truncation=True, padding="max_length", max_length=512)        tokenized_dataset = dataset.map(            tokenize_function,            batched=True,            remove_columns=dataset.column_names,            num_proc=4        )        training_args = TrainingArguments(            output_dir="./lora_output",            per_device_train_batch_size=2,            gradient_accumulation_steps=8,            learning_rate=2e-4,            num_train_epochs=1,            logging_steps=10,            save_strategy="no",            fp16=True,            report_to="mlflow"        )        trainer = Trainer(            model=model,            args=training_args,            train_dataset=tokenized_dataset,            data_collator=DataCollatorForSeq2Seq(tokenizer, padding=True),        )        trainer.train()        # 保存 LoRA 适配器        model.save_pretrained("./lora_output/adapter")        tokenizer.save_pretrained("./lora_output/adapter")        mlflow.log_artifacts("./lora_output/adapter", artifact_path="model")if __name__ == "__main__":    main()src/evaluate_model.py(评估 + 注册模型)

import osimport mlflowfrom mlflow.models import infer_signaturedef main():    client = mlflow.MlflowClient(tracking_uri=os.getenv("MLFLOW_TRACKING_URI"))    run_id = os.getenv("CI_MLFLOW_RUN_ID")  # 从 CI 传入    # 简化评估:检查模型文件是否存在    model_path = f"mlruns/.../{run_id}/artifacts/model"  # 实际需解析    accuracy = 0.85  # 模拟评估结果    # 注册模型到 Registry    model_uri = f"runs:/{run_id}/model"    result = mlflow.register_model(model_uri, name="qwen-lora-zh")    # 设置 Stage(Staging)    client.transition_model_version_stage(        name="qwen-lora-zh",        version=result.version,        stage="Staging"    )    # 写入部署标志    if accuracy >= 0.8:        with open("deploy_flag", "w") as f:            f.write("true")        print(f"✅ Model registered as version {result.version}, ready for deployment.")    else:        with open("deploy_flag", "w") as f:            f.write("false")if __name__ == "__main__":    main()docker/Dockerfile.vllm

FROM vllm/vllm-openai:latest# 安装中文分词依赖RUN pip install sentencepiece# 复制 LoRA 适配器(由 CI 在构建时注入)COPY lora_output/adapter /app/lora_adapter# 启动脚本COPY docker/entrypoint.sh /app/entrypoint.shRUN chmod +x /app/entrypoint.shEXPOSE 8000ENTRYPOINT ["/app/entrypoint.sh"]docker/entrypoint.sh

#!/bin/bashMODEL_PATH="/models/Qwen-7B-Chat"LORA_PATH="/app/lora_adapter"# 启动 vLLM,加载基础模型 + LoRApython -m vllm.entrypoints.openai.api_server \  --model $MODEL_PATH \  --lora-modules zh-adapter=$LORA_PATH \  --tokenizer-mode auto \  --tensor-parallel-size 1 \  --port 8000k8s/deployment.yaml.tpl

stages:  - train  - evaluate  - deployvariables:  MLFLOW_TRACKING_URI: "http://mlflow.internal:5000"  REGISTRY: "registry.internal.example.com"  IMAGE_NAME: "$REGISTRY/qwen-lora:$CI_COMMIT_SHORT_SHA"before_script:  - pip install -r requirements.txttrain:  stage: train  script:    - python src/train_lora.py  artifacts:    paths:      - lora_output/    expire_in: 1 weekevaluate:  stage: evaluate  script:    - export CI_MLFLOW_RUN_ID=$(cat mlflow_run_id.txt)  # 实际需从 train 阶段获取    - python src/evaluate_model.py    - cat deploy_flag  dependencies:    - train  artifacts:    paths:      - deploy_flag      - lora_output/deploy-prod:  stage: deploy  script:    # 构建镜像    - cp -r lora_output/adapter docker/    - docker build -f docker/Dockerfile.vllm -t $IMAGE_NAME docker/    - docker push $IMAGE_NAME    # 渲染 K8s YAML 并部署    - sed "s|{{ .Image }}|$IMAGE_NAME|g" k8s/deployment.yaml.tpl > k8s/deployment.yaml    - kubectl apply -f k8s/deployment.yaml  dependencies:    - evaluate  only:    variables:      - $CI_COMMIT_BRANCH == "main"  when: on_success  environment:    name: production  rules:    - exists:        - deploy_flag      allow_failure: false    - if: '$(cat deploy_flag) == "true"'.gitlab-ci.yml(关键:自动触发 K8s 部署)

stages:  - train  - evaluate  - deployvariables:  MLFLOW_TRACKING_URI: "http://mlflow.internal:5000"  REGISTRY: "registry.internal.example.com"  IMAGE_NAME: "$REGISTRY/qwen-lora:$CI_COMMIT_SHORT_SHA"before_script:  - pip install -r requirements.txttrain:  stage: train  script:    - python src/train_lora.py  artifacts:    paths:      - lora_output/    expire_in: 1 weekevaluate:  stage: evaluate  script:    - export CI_MLFLOW_RUN_ID=$(cat mlflow_run_id.txt)  # 实际需从 train 阶段获取    - python src/evaluate_model.py    - cat deploy_flag  dependencies:    - train  artifacts:    paths:      - deploy_flag      - lora_output/deploy-prod:  stage: deploy  script:    # 构建镜像    - cp -r lora_output/adapter docker/    - docker build -f docker/Dockerfile.vllm -t $IMAGE_NAME docker/    - docker push $IMAGE_NAME    # 渲染 K8s YAML 并部署    - sed "s|{{ .Image }}|$IMAGE_NAME|g" k8s/deployment.yaml.tpl > k8s/deployment.yaml    - kubectl apply -f k8s/deployment.yaml  dependencies:    - evaluate  only:    variables:      - $CI_COMMIT_BRANCH == "main"  when: on_success  environment:    name: production  rules:    - exists:        - deploy_flag      allow_failure: false    - if: '$(cat deploy_flag) == "true"'部署后调用示例

# 调用 vLLM OpenAI 兼容 APIcurl http://qwen-lora-service:8000/v1/chat/completions \  -H "Content-Type: application/json" \  -d '{    "model": "qwen-7b",    "messages": [{"role": "user", "content": "你好!"}],    "lora_name": "zh-adapter"  }'增强建议(生产级)




功能实现方式
自动回滚监控服务健康,失败时 kubectl rollout undo
多环境为 dev/staging/prod 创建不同 K8s namespace
模型版本路由Ingress + Header 路由到不同模型版本
GPU 资源隔离使用 K8s Device Plugin + Resource Quota
日志监控Fluentd + Prometheus + Grafana

Die von den Nutzern eingestellten Information und Meinungen sind nicht eigene Informationen und Meinungen der DOLC GmbH.
您需要登录后才可以回帖 登录 | 注册 微信登录

本版积分规则

Archiver|手机版|AGB|Impressum|Datenschutzerklärung|萍聚社区-德国热线-德国实用信息网

GMT+1, 2025-11-16 15:41 , Processed in 0.110194 second(s), 30 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表