Deepseek 模型本地化部署、训练与网站集成指南

目录

  1. Deepseek 模型概述
  2. 环境准备
  3. 本地部署 Deepseek
  4. 模型训练与微调
  5. 网站集成
  6. 性能优化
  7. 常见问题解答

使用ollama部署见专栏下篇文章

1. Deepseek 模型概述

Deepseek 是由深度求索科技开发的大型语言模型系列,具有出色的中文理解和生成能力。该模型系列提供了不同参数规模的版本,从轻量级到大规模均有覆盖。

主要模型系列:

  • Deepseek-LLM: 基础大语言模型
  • Deepseek-Coder: 专注于代码生成的模型
  • Deepseek-VL: 视觉语言模型
  • Deepseek-MoE: 混合专家模型

2. 环境准备

2.1 硬件要求

根据模型的规模,硬件要求会有所不同:

模型规模 最低 GPU 显存 推荐配置
7B 16GB NVIDIA RTX 3090/4090 或 A100
13B 24GB NVIDIA A10G 或 A100
70B 80GB+ 多卡设置或 NVIDIA A100 80GB

2.2 软件环境

# 创建虚拟环境
conda create -n deepseek python=3.10
conda activate deepseek

# 安装 PyTorch (CUDA 11.8 版本示例)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

# 安装 Deepseek 相关依赖
pip install transformers>=4.34.0
pip install accelerate>=0.23.0
pip install bitsandbytes>=0.41.0
pip install sentencepiece
pip install einops

3. 本地部署 Deepseek

3.1 下载模型

从 Hugging Face 下载 Deepseek 模型:

from huggingface_hub import snapshot_download

# 下载 Deepseek-LLM-7B 模型
model_path = snapshot_download(
    repo_id="deepseek-ai/deepseek-llm-7b-base",
    local_dir="./models/deepseek-llm-7b-base"
)

或使用命令行:

git lfs install
git clone https://huggingface.co/deepseek-ai/deepseek-llm-7b-base

3.2 基础推理

使用 Transformers 库进行简单推理:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

# 加载模型和分词器
model_path = "./models/deepseek-llm-7b-base"  # 或使用 "deepseek-ai/deepseek-llm-7b-base"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

# 构建输入
input_text = "你好,请介绍一下你自己"
inputs = tokenizer(input_text, return_tensors="pt").to(model.device)

# 生成回答
with torch.no_grad():
    outputs = model.generate(
        inputs["input_ids"],
        max_new_tokens=512,
        do_sample=True,
        temperature=0.7,
        top_p=0.95,
    )

# 解码输出
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(response)

3.3 量化部署

对于内存受限的环境,可以使用量化技术降低内存占用:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

# 4-bit 量化配置
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
)

# 加载量化模型
model_path = "deepseek-ai/deepseek-llm-7b-base"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    quantization_config=quantization_config,
    device_map="auto",
)

3.4 使用 vLLM 加速推理

vLLM 是一个高效的 LLM 推理引擎,可以显著提升推理速度:

pip install vllm

使用 vLLM 部署 Deepseek:

from vllm import LLM, SamplingParams

# 初始化 LLM
llm = LLM(
    model="deepseek-ai/deepseek-llm-7b-base",
    dtype="bfloat16",
    gpu_memory_utilization=0.8,
)

# 设置生成参数
sampling_params = SamplingParams(
    temperature=0.7,
    top_p=0.95,
    max_tokens=512,
)

# 生成回答
prompts = ["你好,请介绍一下你自己"]
outputs = llm.generate(prompts, sampling_params)

# 打印结果
for output in outputs:
    print(output.text)

3.5 创建本地 API 服务

使用 FastAPI 创建本地 API 服务:

# api_server.py
from fastapi import FastAPI, Request
import uvicorn
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

app = FastAPI()

# 全局模型和分词器
model_path = "deepseek-ai/deepseek-llm-7b-base"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

@app.post("/generate")
async def generate(request: Request):
    data = await request.json()
    prompt = data.get("prompt", "")
    max_tokens = data.get("max_tokens", 512)
    temperature = data.get("temperature", 0.7)
    
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    
    with torch.no_grad():
        outputs = model.generate(
            inputs["input_ids"],
            max_new_tokens=max_tokens,
            do_sample=True,
            temperature=temperature,
            top_p=0.95,
        )
    
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return {"response": response}

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

启动服务:

python api_server.py

4. 模型训练与微调

4.1 数据准备

准备训练数据格式:

[
    {
        "instruction": "解释量子计算的基本原理",
        "output": "量子计算是一种利用量子力学现象(如叠加和纠缠)进行计算的技术..."
    },
    {
        "instruction": "写一篇关于人工智能伦理的短文",
        "output": "人工智能伦理是一个日益重要的领域,涉及到 AI 系统的设计、开发和应用..."
    }
]

4.2 使用 LoRA 进行高效微调

LoRA (Low-Rank Adaptation) 是一种参数高效的微调方法,可以大大降低显存需求:

from peft import prepare_model_for_kbit_training, LoraConfig, get_peft_model

# LoRA 配置
lora_config = LoraConfig(
    r=16,  # LoRA 矩阵的秩
    lora_alpha=32,  # 缩放因子
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj",
    ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# 准备模型
model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, lora_config)

4.3 训练脚本

import torch
from transformers import (
    AutoModelForCausalLM, 
    AutoTokenizer, 
    BitsAndBytesConfig, 
    TrainingArguments
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from trl import SFTTrainer
import json

# 1. 加载数据
with open("training_data.json", "r", encoding="utf-8") as f:
    data = json.load(f)

# 2. 准备数据集
from datasets import Dataset
dataset = Dataset.from_list(data)

# 3. 初始化量化配置
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
)

# 4. 加载基础模型和分词器
model_path = "deepseek-ai/deepseek-llm-7b-base"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    quantization_config=quantization_config,
    device_map="auto",
)

# 5. 配置 LoRA
lora_config = LoraConfig(
    r=16,
    lora_alpha=32,
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",
        "gate_proj", "up_proj", "down_proj",
    ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)

# 6. 准备 LoRA 模型
model = prepare_model_for_kbit_training(model)
model = get_peft_model(model, lora_config)

# 7. 设置训练参数
training_arguments = TrainingArguments(
    output_dir="./deepseek-lora-output",
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    num_train_epochs=3,
    logging_steps=10,
    save_steps=100,
    save_total_limit=3,
    report_to="tensorboard",
    fp16=True,
)

# 8. 创建训练器
def formatting_func(examples):
    texts = []
    for instruction, output in zip(examples["instruction"], examples["output"]):
        text = f"<|user|>\n{instruction}\n<|assistant|>\n{output}<|endoftext|>"
        texts.append(text)
    return {"text": texts}

trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    formatting_func=formatting_func,
    args=training_arguments,
    tokenizer=tokenizer,
    max_seq_length=2048,
)

# 9. 开始训练
trainer.train()

# 10. 保存模型
trainer.save_model("./deepseek-finetuned")

# 11. 合并 LoRA 权重到基础模型 (可选)
from peft import PeftModel
base_model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="auto"
)
lora_model = PeftModel.from_pretrained(base_model, "./deepseek-finetuned")
merged_model = lora_model.merge_and_unload()
merged_model.save_pretrained("./deepseek-merged")

5. 网站集成

5.1 使用 JavaScript 与模型 API 交互

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Deepseek 演示</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        .chat-container {
            border: 1px solid #ddd;
            padding: 20px;
            height: 400px;
            overflow-y: auto;
            margin-bottom: 20px;
            border-radius: 8px;
        }
        .user-message {
            background-color: #e6f7ff;
            padding: 10px;
            border-radius: 8px;
            margin-bottom: 10px;
        }
        .bot-message {
            background-color: #f0f0f0;
            padding: 10px;
            border-radius: 8px;
            margin-bottom: 10px;
        }
        .input-container {
            display: flex;
        }
        #user-input {
            flex: 1;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            margin-right: 10px;
        }
        button {
            background-color: #1890ff;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 4px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>Deepseek 对话演示</h1>
    <div class="chat-container" id="chat-container"></div>
    <div class="input-container">
        <input type="text" id="user-input" placeholder="输入您的问题...">
        <button id="send-button">发送</button>
    </div>

    <script>
        const chatContainer = document.getElementById('chat-container');
        const userInput = document.getElementById('user-input');
        const sendButton = document.getElementById('send-button');

        function addMessage(text, isUser) {
            const messageDiv = document.createElement('div');
            messageDiv.className = isUser ? 'user-message' : 'bot-message';
            messageDiv.textContent = text;
            chatContainer.appendChild(messageDiv);
            chatContainer.scrollTop = chatContainer.scrollHeight;
        }

        async function sendMessage() {
            const message = userInput.value.trim();
            if (!message) return;

            // 添加用户消息到聊天框
            addMessage(message, true);
            userInput.value = '';
            userInput.disabled = true;
            sendButton.disabled = true;

            try {
                // 发送请求到您的本地API
                const response = await fetch('http://localhost:8000/generate', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({
                        prompt: message,
                        max_tokens: 512,
                        temperature: 0.7,
                    }),
                });

                const data = await response.json();
                // 添加模型回复到聊天框
                addMessage(data.response, false);
            } catch (error) {
                console.error('Error:', error);
                addMessage('抱歉,连接服务器时出现错误', false);
            } finally {
                userInput.disabled = false;
                sendButton.disabled = false;
                userInput.focus();
            }
        }

        sendButton.addEventListener('click', sendMessage);
        userInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') sendMessage();
        });

        // 初始欢迎消息
        addMessage('你好!我是 Deepseek 助手,有什么可以帮助你的吗?', false);
    </script>
</body>
</html>

5.2 使用 Python 框架集成

Flask 示例
from flask import Flask, render_template, request, jsonify
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

app = Flask(__name__)

# 全局模型和分词器
model_path = "./deepseek-finetuned"  # 使用微调后的模型
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

@app.route('/')
def index():
    return render_template('index.html')  # 创建HTML模板

@app.route('/api/chat', methods=['POST'])
def chat():
    data = request.json
    user_message = data.get('message', '')
    
    # 构建输入
    prompt = f"<|user|>\n{user_message}\n<|assistant|>\n"
    inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
    
    # 生成回答
    with torch.no_grad():
        outputs = model.generate(
            inputs["input_ids"],
            max_new_tokens=512,
            do_sample=True,
            temperature=0.7,
            top_p=0.95,
        )
    
    # 处理回答
    full_response = tokenizer.decode(outputs[0], skip_special_tokens=False)
    assistant_response = full_response.split("<|assistant|>\n")[-1].replace("<|endoftext|>", "").strip()
    
    return jsonify({"response": assistant_response})

if __name__ == '__main__':
    app.run(debug=True)
Django 示例
# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
import json

# 全局模型和分词器
model_path = "./deepseek-finetuned"
tokenizer = AutoTokenizer.from_pretrained(model_path)
model = AutoModelForCausalLM.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="auto",
)

def index(request):
    return render(request, 'index.html')

@csrf_exempt
def chat_api(request):
    if request.method == 'POST':
        data = json.loads(request.body)
        user_message = data.get('message', '')
        
        # 构建输入
        prompt = f"<|user|>\n{user_message}\n<|assistant|>\n"
        inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
        
        # 生成回答
        with torch.no_grad():
            outputs = model.generate(
                inputs["input_ids"],
                max_new_tokens=512,
                do_sample=True,
                temperature=0.7,
                top_p=0.95,
            )
        
        # 处理回答
        full_response = tokenizer.decode(outputs[0], skip_special_tokens=False)
        assistant_response = full_response.split("<|assistant|>\n")[-1].replace("<|endoftext|>", "").strip()
        
        return JsonResponse({"response": assistant_response})
    
    return JsonResponse({"error": "仅支持 POST 请求"}, status=400)

6. 性能优化

6.1 模型量化与优化

除了前面提到的 4-bit 量化,还可以尝试:

  1. GPTQ 量化:
pip install auto-gptq
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig

quantize_config = BaseQuantizeConfig(
    bits=4,
    group_size=128,
    desc_act=False,
)

# 量化模型
model = AutoGPTQForCausalLM.from_pretrained(
    model_path,
    quantize_config=quantize_config,
)
  1. ONNX 格式转换:
pip install optimum
from optimum.onnxruntime import ORTModelForCausalLM

# 转换为 ONNX 格式
model = ORTModelForCausalLM.from_pretrained(
    model_path,
    export=True,
    provider="CUDAExecutionProvider",
)

6.2 推理优化

  1. 使用持久连接:
    在网站和 API 之间使用 WebSocket 或持久化 HTTP 连接,减少连接建立的开销。

  2. 实现请求队列:
    使用 Redis 或 RabbitMQ 等消息队列系统管理高负载下的请求。

  3. 模型并行推理:

from concurrent.futures import ThreadPoolExecutor
import queue

request_queue = queue.Queue()
response_dict = {}

def worker():
    while True:
        request_id, prompt = request_queue.get()
        # 处理推理请求
        inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
        with torch.no_grad():
            outputs = model.generate(
                inputs["input_ids"],
                max_new_tokens=512,
            )
        response = tokenizer.decode(outputs[0], skip_special_tokens=True)
        response_dict[request_id] = response
        request_queue.task_done()

# 启动工作线程
executor = ThreadPoolExecutor(max_workers=1)
executor.submit(worker)

7. 常见问题解答

7.1 模型加载失败

问题: CUDA out of memory 错误。
解决方案:

  • 尝试 4-bit 或 8-bit 量化
  • 减小批处理大小
  • 使用较小的模型版本

7.2 生成速度慢

问题: 模型响应时间长。
解决方案:

  • 使用 vLLM 加速推理
  • 应用 ONNX 转换
  • 减少生成的最大 token 数
  • 考虑使用更小的模型

7.3 训练不稳定

问题: 微调过程中损失值不收敛或出现 NaN。
解决方案:

  • 降低学习率
  • 增加梯度截断值
  • 检查数据集格式和质量
  • 增加 warmup 步数

7.4 内存泄漏

问题: 长时间运行后内存占用持续增加。
解决方案:

  • 确保每次推理后调用 torch.cuda.empty_cache()
  • 考虑定期重启服务
  • 检查代码中可能的引用循环

7.5 模型输出质量问题

问题: 微调后的模型输出质量下降。
解决方案:

  • 检查训练数据质量
  • 降低训练 epoch 数,避免过拟合
  • 尝试不同的微调参数
  • 增加训练数据的多样性
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐