【大模型】部署lora微调后的LLM(以百川为例)

接上篇,我们可以使用lora的方法微调LLM。

和微调相对的另一个问题是,我们要如何使用大模型。如果直接使用transformer加载大模型,那只能单线程使用,因为推理过程没有经过优化。如果想要多人同时使用大模型,那么需要使用专门的大模型推理加速框架,比如vllm,tgi。

vllm,tgi加载大模型的方法可以查看官网。这些框架成功加载LLM后,还有两个大坑等着我们:对话模板,加载微调模型。

关于对话模板。首先,大模型是补全模型,也就是说,我们输入一句话,模型接着这句话往下续写,补全后文。这和对话是很不一样的。我们需要一个特殊的prompt,使得模型可以意识到,它续写的时候需要按照对话这种情境来续写。不同的模型有不同的prompt,真正的问题是需要包裹在prompt里面的。transformer加载开源LLM的时候,一般会提供chat接口,背后已经将问题转化成了prompt包裹的格式。当我们需要使用其他加速框架部署大模型时,需要自己完成这一步:要么在传入问题时直接传prompt格式的问题,或者框架有模板接口可以按照自定义模板在后台自动化完成这种格式转化。(一般是写jinja文件)tgi在对话模板上的支持很不好。vllm则可以在启动时显式指定chat-template。因此推荐使用vllm。

关于加载微调模型。vllm0.4.0版开始可以支持,但是之前不能支持(即使将lora微调后的参数合并回原始模型了,也不能加载)。tgi则可以直接加载参数合并之后的模型。但是因为模板的问题,tgi还是不适用于没有给出明文prompt的LLM。

附录:将微调参数合并回原始模型的代码
import argparse

import torch
from peft import PeftModel, PeftConfig
from transformers import (
    AutoModel,
    AutoTokenizer,
    BloomForCausalLM,
    BloomTokenizerFast,
    AutoModelForCausalLM,
    LlamaTokenizer,
    LlamaForCausalLM,
    AutoModelForSequenceClassification,
)

MODEL_CLASSES = {
    "bloom": (BloomForCausalLM, BloomTokenizerFast),
    "chatglm": (AutoModel, AutoTokenizer),
    "llama": (LlamaForCausalLM, LlamaTokenizer),
    "baichuan": (AutoModelForCausalLM, AutoTokenizer),
    "auto": (AutoModelForCausalLM, AutoTokenizer),
}


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model_type', default="baichuan", type=str, required=False)
    parser.add_argument('--tokenizer_path', default=None, type=str,
                        help="Please specify tokenization path.")

    parser.add_argument('--output_dir', default='./merged', type=str)
    args = parser.parse_args()


    base_model_path = "../../Baichuan_Inc/Baichuan_Inc/Baichuan"
    lora_model_path = "baichuan_fineturn/risk_combine_output"
    output_dir = args.output_dir
    peft_config = PeftConfig.from_pretrained(lora_model_path)
    model_class, tokenizer_class = MODEL_CLASSES[args.model_type]

    # 模型加载
    if peft_config.task_type == "SEQ_CLS":
        if args.model_type == "chatglm":
            raise ValueError("chatglm does not support sequence classification")
        base_model = AutoModelForSequenceClassification.from_pretrained(
            base_model_path,
            num_labels=1,
            load_in_8bit=False,
            torch_dtype=torch.float32,
            trust_remote_code=True,
            device_map="auto",
        )
    else:
        base_model = model_class.from_pretrained(
            base_model_path,
            load_in_8bit=False,
            torch_dtype=torch.float16,
            trust_remote_code=True,
            device_map="auto",
        )
    
    # 分词器加载
    if args.tokenizer_path:
        tokenizer = tokenizer_class.from_pretrained(args.tokenizer_path, trust_remote_code=True)
    else:
        tokenizer = tokenizer_class.from_pretrained(base_model_path, trust_remote_code=True)

    # 修改词表大小
    # if args.resize_emb:
    #     base_model_token_size = base_model.get_input_embeddings().weight.size(0)
    #     if base_model_token_size != len(tokenizer):
    #         base_model.resize_token_embeddings(len(tokenizer))

    # 初始化Peft新模型
    new_model = PeftModel.from_pretrained(
        base_model,
        lora_model_path,
        device_map="auto",
        torch_dtype=torch.float16,
    )
    new_model.eval()
    new_base_model = new_model.merge_and_unload()

    tokenizer.save_pretrained(output_dir)
    new_base_model.save_pretrained(output_dir, safe_serialization=False, max_shard_size='10GB')

if __name__ == '__main__':
    main()
vllm在openshift上部署deployment的demo

(这里直接部署的量化版通义千问,参数合并后的百川用同样的方式部署即可。需要特别注意的是参数gpu-memory-utilization,它要求一开始就被分配这么多的GPU,如果不能分配,会报错崩溃。如果分配了这么多GPU,仍然不能满足模型的需要,也会报错。所以,要确保分配的比例是当前空余GPU空余资源可满足的,然后保证足够加载模型)

kind: Deployment
apiVersion: apps/v1
metadata:
  name: base-llm-server-vllm
  namespace: YOUR_NAMESPACE
spec:
  replicas: 1
  selector:
    matchLabels:
      app: base-llm-server-vllm
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: base-llm-server-vllm
    spec:
      nodeSelector:
        kubernetes.io/hostname: YOUR_COMPUTE_NODE
        kubernetes.io/role: gpu
      restartPolicy: Always
      schedulerName: default-scheduler
      terminationGracePeriodSeconds: 30
      securityContext:
        runAsUser: 0
      containers:
        - resources:
            limits:
              cpu: '6'
              memory: 64Gi
              nvidia.com/gpu: '1'
            requests:
              cpu: 200m
              memory: 16Gi
              nvidia.com/gpu: '1'
          terminationMessagePath: /dev/termination-log
          name: vllm-latest-container
          command:
            - python3
            - '-m'
            - vllm.entrypoints.openai.api_server
            - '--model=/data/Qwen-AWQ'
            - '--gpu-memory-utilization=0.3'
            - '--trust-remote-code'
            - '--disable-log-requests'
            - '--chat-template=/data/Qwen-AWQ/qwen1_5_14B_template.jinja'
            - '--dtype=float16'
            - '--quantization=awq'
          env:
            - name: HUGGING_FACE_HUB_TOKEN
              value: <secret>
            - name: NVIDIA_VISIBLE_DEVICES
              value: all
            - name: CUDA_VISIBLE_DEVICES
              value: '1'
          ports:
            - containerPort: 8000
              protocol: TCP
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: data-volume
              mountPath: /data
              subPath: models
          terminationMessagePolicy: File
          image: VLLM-OPENAI-IMAGE:v0.4.0
      volumes:
        - name: data-volume
          persistentVolumeClaim:
            claimName: text-gen-pvc-local
      dnsPolicy: ClusterFirst
      tolerations:
        - key: nvidia.com/gpu
          effect: NoSchedule
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  revisionHistoryLimit: 10
  progressDeadlineSeconds: 600
自定义的对话模板(jinja)
{% for message in messages %}
{% if loop.first and messages[0]['role'] != 'system' %}
{{ '<|im_start|>system\nYou are a helpful assistant<|im_end|>\n' }}
{% endif %}
{{'<|im_start|>' + message['role'] + '\n' + message['content']}}
{% if (loop.last and add_generation_prompt) or not loop.last %}
{{ '<|im_end|>' + '\n'}}
{% endif %}
{% endfor %}
{% if add_generation_prompt and messages[-1]['role'] != 'assistant' %}
{{ '<|im_start|>assistant\n' }}
{% endif %}

通过restful调用大模型

POST http://base-llm-server-vllm.com/v1/chat/completions 

{
"model": "/data/Qwen-AWQ",
"stream": true, #流式响应,不需要可以关闭
"messages": [
        {"role": "user", "content": "你是谁?"}
    ]
}

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值