1. 从零上手大模型我的DeepSeek学习路线复盘第一次认真接触DeepSeek是在一个内部技术分享会上当时某开发者演示了一个用大模型做代码补全的Demo效果出乎意料地好。会后我花了大概两周时间把DeepSeek系列模型的文档、论文和开源代码翻了一遍边学边记慢慢攒出了一份自己的学习笔记。这份笔记不是官方文档的搬运而是我在实际跑通推理、微调、部署这几个环节之后把踩过的坑和想明白的道理整理出来的东西。DeepSeek是国产大模型里比较有代表性的一系列模型覆盖了从通用对话到代码生成、数学推理等多个方向。它能做的事情很多文本生成、代码补全、逻辑推理、多轮对话、文档问答基本上主流大模型能干的事它都能干。但真正让我觉得值得深入研究的是它在架构设计上的一些取舍——比如MoE混合专家结构的引入、训练成本的优化思路、以及推理时的一些工程技巧。这些设计直接影响了我们怎么用它、怎么调它、怎么部署它。这份笔记适合几类人看一是刚接触大模型、想找一个国产模型上手练手的开发者二是已经在用其他大模型、想对比一下DeepSeek差异的工程师三是对MoE架构和推理优化感兴趣、想从工程角度理解大模型的技术人员。不管你之前有没有跑过模型我都会尽量把每一步讲清楚包括为什么要这么做、不这么做会出什么问题。我自己的背景是后端开发出身之前做过一些推荐系统和数据处理的工作对深度学习只能算了解皮毛。所以这份笔记的视角是偏工程的不会堆太多公式更多是从“怎么用起来”和“为什么这么设计”两个角度切入。如果你也是工程背景应该会觉得比较亲切。2. 核心架构拆解DeepSeek到底特殊在哪2.1 MoE架构的工程意义DeepSeek系列里最值得聊的就是MoE架构。传统的稠密模型每次推理都会激活全部参数参数量越大计算量越大推理成本线性上升。MoE的思路是把模型拆成多个“专家”子网络每次输入只激活其中一小部分专家这样总参数量可以做得很大但实际计算量只跟激活的专家数量相关。打个比方稠密模型像是一家所有科室都同时开门的医院不管你看什么病所有医生都在上班MoE则像是分诊制你挂什么号就只叫对应的科室其他科室的医生可以休息。这样一来医院可以雇佣更多专科医生总参数量大但每次看病的成本并不会等比例上升。DeepSeek的MoE实现里有几个关键参数需要理解专家总数模型里一共有多少个专家子网络。数量越多模型容量越大但路由决策也越复杂。激活专家数每次推理激活几个专家。通常远小于专家总数比如总共几十个专家只激活两三个。路由机制决定输入送给哪些专家的算法。常见的是Top-K路由即选得分最高的K个专家。我实测下来MoE模型在推理时的显存占用主要取决于总参数量因为所有专家权重都要加载到显存但计算量取决于激活参数量。这意味着MoE对显存的要求高但对算力的要求相对低。这个特性直接影响了部署方案的选择——如果你显存不够MoE模型可能跑不起来但如果显存够它的推理速度会比同等总参数量的稠密模型快不少。2.2 训练策略与成本控制DeepSeek在训练成本上的优化思路也值得一说。大模型训练最贵的是算力和数据DeepSeek在这方面做了几个比较聪明的取舍。首先是数据配比的优化。不是所有数据都同等重要代码、数学、逻辑推理类的数据对模型能力的提升更明显但这类数据获取成本高。DeepSeek在预训练阶段对数据做了精细的筛选和配比把有限的高质量数据用在刀刃上。我在做微调的时候也发现了类似规律用少量高质量领域数据微调效果往往比用大量低质量数据好。其次是训练流程的改进。DeepSeek采用了分阶段训练的策略先在大规模通用数据上做预训练再在高质量数据上做继续预训练最后做对齐微调。这种分阶段的方式让每一阶段的训练目标更明确避免了“一锅炖”导致的效率低下。还有一个点是混合精度训练和梯度检查点技术的使用。混合精度训练用FP16或BF16做前向和反向计算用FP32保存权重更新既节省显存又保证数值稳定性。梯度检查点则是用计算换显存在前向传播时不保存所有中间激活值反向传播时重新计算这样可以用更少的显存训练更大的模型。这两个技术我在自己跑微调的时候都用上了确实能明显降低显存门槛。2.3 推理优化关键技术推理阶段是大多数开发者最关心的部分因为直接关系到响应速度和部署成本。DeepSeek在推理优化上做了几件事KV Cache优化。自回归生成时每次生成一个新token都要重新计算之前所有token的Key和Value矩阵计算量随序列长度平方增长。KV Cache把这些中间结果缓存下来避免重复计算。但KV Cache本身占显存序列越长占用越大。DeepSeek对KV Cache做了压缩和分页管理降低了长序列推理的显存压力。量化支持。DeepSeek提供了多种量化版本比如INT8、INT4量化。量化是用更低的数值精度表示权重和激活值牺牲一点精度换取显存和速度的优化。我实测INT8量化后模型大小减半推理速度提升约30%精度损失在可接受范围内。INT4量化更激进适合显存特别紧张的场景但精度损失需要根据具体任务评估。批处理与并发。推理服务通常需要同时处理多个请求批处理能把多个请求合并成一个批次一起计算提高GPU利用率。但批处理会增加单次延迟需要根据业务场景权衡。DeepSeek的推理框架支持动态批处理可以根据请求量自动调整批次大小。3. 环境搭建与模型获取实操3.1 硬件与软件环境准备跑DeepSeek之前先要确认硬件条件。不同规模的模型对硬件要求差别很大模型规模最低显存要求FP16推荐显存INT8量化适用场景7B级别16GB8GB个人开发、小规模测试13B级别28GB14GB中等规模应用30B级别60GB30GB企业级应用100B级别多卡并行多卡并行大规模服务我自己的测试环境是一台单卡24GB显存的机器跑7B级别模型FP16勉强够用但序列长度一长就OOM显存溢出。后来换成INT8量化版本显存占用降到10GB左右跑起来就舒服多了。如果你手头只有消费级显卡比如12GB或16GB显存建议直接从量化版本入手。软件环境方面Python 3.9以上、PyTorch 2.0以上是基本要求。CUDA版本要和PyTorch版本匹配这个坑我踩过——装了个CUDA 12.1的驱动结果PyTorch装的是CUDA 11.8的版本跑起来各种报错。后来统一成CUDA 11.8 PyTorch 2.0.1才稳定。# 创建虚拟环境 python -m venv deepseek_env source deepseek_env/bin/activate # 安装PyTorch根据你的CUDA版本选择 pip install torch2.0.1cu118 torchvision0.15.2cu118 --index-url https://download.pytorch.org/whl/cu118 # 安装transformers和其他依赖 pip install transformers4.35.0 accelerate0.24.0 sentencepiece0.1.99注意transformers版本不要盲目追新有些新版本对DeepSeek的支持还不完善建议先用官方推荐的版本组合。3.2 模型下载与加载模型权重可以从官方渠道获取。下载之前先确认磁盘空间7B模型的FP16权重约14GBINT8量化版约7GBINT4量化版约3.5GB。下载方式一般有两种直接用git clone拉取或者用huggingface-hub的snapshot_download。from huggingface_hub import snapshot_download snapshot_download( repo_iddeepseek-ai/deepseek-model-7b, local_dir./models/deepseek-7b, local_dir_use_symlinksFalse )加载模型的时候有几个参数需要特别注意from transformers import AutoModelForCausalLM, AutoTokenizer model AutoModelForCausalLM.from_pretrained( ./models/deepseek-7b, torch_dtypetorch.float16, # 数据类型 device_mapauto, # 自动分配设备 trust_remote_codeTrue, # 信任远程代码 load_in_8bitTrue # 8bit量化加载 )device_mapauto会让accelerate库自动决定每一层放在哪个设备上单卡情况下就是全放GPU多卡情况下会自动切分。trust_remote_codeTrue是因为DeepSeek的模型定义可能包含自定义代码需要显式信任才能加载。load_in_8bitTrue启用8bit量化能显著降低显存占用。我遇到过一个问题加载模型时报错说某个自定义模块找不到。排查后发现是transformers版本太旧不支持DeepSeek的自定义模型类。升级到4.35.0之后问题解决。所以如果你也遇到类似报错先检查版本。3.3 推理测试与效果验证模型加载成功后先跑一个简单的推理测试确认基本功能正常tokenizer AutoTokenizer.from_pretrained(./models/deepseek-7b, trust_remote_codeTrue) input_text 请用Python写一个快速排序算法 inputs tokenizer(input_text, return_tensorspt).to(cuda) outputs model.generate( **inputs, max_new_tokens256, temperature0.7, top_p0.9, do_sampleTrue ) print(tokenizer.decode(outputs[0], skip_special_tokensTrue))这里几个生成参数需要理解max_new_tokens最多生成多少个新token。设太小可能回答不完整设太大浪费计算资源。temperature控制随机性。值越高输出越随机值越低输出越确定。代码生成建议用0.2-0.5创意写作可以用0.7-1.0。top_p核采样参数。只从累积概率达到top_p的token中采样避免生成低概率的奇怪内容。do_sample是否采样。设为False就是贪心解码每次选概率最高的token输出确定但可能重复。我测试下来DeepSeek在代码生成任务上表现不错简单的排序、查找、字符串处理都能一次写对。但在复杂逻辑推理上偶尔会出错比如多步数学计算容易中间步骤算错。这个后面在微调部分会讲怎么改善。4. 微调实战让模型适配你的业务场景4.1 微调方案选型微调大模型有好几种方案从便宜到贵排列LoRA低秩适配是最常用的方案。它不改动原始模型权重而是在每一层旁边加一个小型的低秩矩阵训练时只更新这些小矩阵。优点是显存占用小、训练快、可以多个LoRA切换使用。缺点是效果上限不如全量微调。QLoRA是LoRA的量化版本把原始模型量化到4bit再在上面加LoRA。显存占用进一步降低7B模型用QLoRA微调只需要不到10GB显存。代价是训练速度稍慢精度有轻微损失。全量微调更新所有参数效果最好但显存要求极高。7B模型全量微调至少需要60GB以上显存一般个人开发者玩不起。继续预训练是在大量领域数据上继续训练适合有海量领域数据的情况。成本最高但能让模型真正“学会”领域知识。我的建议是先用LoRA快速验证效果如果效果不够再考虑QLoRA或全量微调。大多数业务场景LoRA就够用了。4.2 数据准备与格式处理微调数据质量比数量重要。我试过用1000条高质量数据微调效果比用10000条低质量数据好。数据格式一般是instruction-input-output的三元组[ { instruction: 将以下文本翻译成英文, input: 今天天气很好, output: The weather is nice today. }, { instruction: 写一个Python函数计算斐波那契数列, input: , output: def fibonacci(n):\n if n 1:\n return n\n return fibonacci(n-1) fibonacci(n-2) } ]数据处理有几个要点去重重复数据会让模型过拟合一定要去重。清洗去掉乱码、HTML标签、特殊字符。平衡不同类别的数据量尽量均衡避免模型偏向某一类。划分留出10%-20%作为验证集监控训练是否过拟合。我踩过一个坑数据里混了一些格式不一致的样本比如有的用中文标点有的用英文标点导致模型输出标点混乱。后来统一清洗了一遍才解决。所以数据清洗这一步千万别省。4.3 LoRA微调完整流程下面是一个完整的LoRA微调脚本框架from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments from peft import LoraConfig, get_peft_model, TaskType from datasets import load_dataset # 加载模型和tokenizer model AutoModelForCausalLM.from_pretrained( ./models/deepseek-7b, torch_dtypetorch.float16, device_mapauto, trust_remote_codeTrue ) tokenizer AutoTokenizer.from_pretrained(./models/deepseek-7b, trust_remote_codeTrue) # 配置LoRA lora_config LoraConfig( task_typeTaskType.CAUSAL_LM, r8, # 低秩矩阵的秩 lora_alpha32, # 缩放系数 lora_dropout0.1, # dropout率 target_modules[q_proj, v_proj] # 目标模块 ) model get_peft_model(model, lora_config) model.print_trainable_parameters() # 输出类似trainable params: 4,194,304 || all params: 6,742,609,920 || trainable%: 0.06%LoRA的几个关键参数r低秩矩阵的秩。越大表达能力越强但参数量也越大。一般4-16够用复杂任务可以到32或64。lora_alpha缩放系数通常设为r的2-4倍。target_modules对哪些层加LoRA。通常加在注意力机制的q_proj和v_proj上也可以加到k_proj、o_proj和FFN层。训练参数配置training_args TrainingArguments( output_dir./lora_output, num_train_epochs3, per_device_train_batch_size4, gradient_accumulation_steps4, learning_rate2e-4, warmup_steps100, logging_steps10, save_steps500, evaluation_strategysteps, eval_steps500, fp16True, report_tonone )gradient_accumulation_steps4表示累积4个批次的梯度再更新一次等效于把批次大小扩大4倍。这是在显存有限的情况下增大有效批次大小的常用技巧。learning_rate2e-4是LoRA微调的常用学习率比全量微调的学习率大一些因为LoRA参数少、需要更快更新。训练完成后LoRA权重会保存成一个小文件通常几MB到几十MB加载时把原始模型和LoRA权重合并即可from peft import PeftModel base_model AutoModelForCausalLM.from_pretrained(./models/deepseek-7b, ...) lora_model PeftModel.from_pretrained(base_model, ./lora_output) merged_model lora_model.merge_and_unload() merged_model.save_pretrained(./merged_model)4.4 微调效果评估与调优微调完之后怎么判断效果好不好我一般从三个维度评估自动指标用BLEU、ROUGE等指标对比生成结果和参考答案。这些指标计算快但只能反映表面相似度不能完全代表质量。人工评估随机抽100条测试样本人工打分。虽然费时但最准确。我通常按准确性、流畅度、相关性三个维度各打1-5分。业务指标如果微调是为了某个具体业务直接看业务指标。比如做客服问答就看回答准确率和用户满意度。如果效果不理想调优方向有几个增加数据量或提高数据质量增大LoRA的r值调整学习率和训练轮数换用QLoRA或全量微调我遇到过一个典型问题模型在训练集上表现很好但在验证集上差很多典型的过拟合。解决办法是增加dropout、减少训练轮数、增加数据量。后来把lora_dropout从0.1调到0.2训练轮数从5降到3过拟合明显缓解。5. 部署与性能优化实战5.1 推理服务部署方案模型微调好之后最终要部署成服务供业务调用。部署方案有几种选择直接加载模型最简单的方式用FastAPI或Flask包一层HTTP接口。适合小规模、低并发的场景。缺点是每次请求都要走完整推理流程延迟较高。vLLM推理引擎专门为大模型推理优化的引擎支持PagedAttention分页注意力和连续批处理吞吐量比直接加载高好几倍。适合中等规模并发。TensorRT-LLMNVIDIA的推理优化框架把模型编译成TensorRT引擎推理速度最快。但编译过程复杂对模型结构有要求。我自己的项目用的是vLLM部署起来比较简单pip install vllm python -m vllm.entrypoints.openai.api_server \ --model ./merged_model \ --tensor-parallel-size 1 \ --dtype float16 \ --max-model-len 4096 \ --gpu-memory-utilization 0.9tensor-parallel-size是张量并行数单卡设为1多卡设为卡数。max-model-len是最大序列长度根据业务需求设置设太大浪费显存。gpu-memory-utilization是GPU显存利用率上限0.9表示用90%显存。vLLM启动后会提供一个兼容OpenAI API的接口可以直接用openai的Python SDK调用from openai import OpenAI client OpenAI(base_urlhttp://localhost:8000/v1, api_keydummy) response client.chat.completions.create( model./merged_model, messages[{role: user, content: 你好}], max_tokens256, temperature0.7 ) print(response.choices[0].message.content)5.2 显存优化技巧显存是大模型部署最稀缺的资源优化显存能直接降低部署成本。几个实用技巧量化INT8量化能把显存占用减半INT4再减半。精度损失在大多数任务上可以接受。我实测INT8量化后7B模型显存从14GB降到7GB推理速度还快了20%左右。KV Cache管理长序列推理时KV Cache占显存很大。可以设置最大KV Cache大小超出部分自动淘汰。vLLM的PagedAttention就是做这个的把KV Cache分成固定大小的页按需分配。梯度检查点如果是训练场景开启梯度检查点能用计算换显存显存占用降低60%以上训练速度慢20%左右。模型并行单卡放不下就多卡。张量并行把每一层的矩阵运算切分到多卡流水线并行把不同层放到不同卡。vLLM和DeepSpeed都支持这些并行策略。5.3 响应速度优化响应速度直接影响用户体验优化方向有几个批处理把多个请求合并成一个批次一起推理GPU利用率更高。vLLM的连续批处理能在请求不断到来的情况下动态组批吞吐量提升明显。投机解码用一个小模型先草拟几个token再用大模型验证。如果大模型认可小模型的草稿就能一次生成多个token速度提升2-3倍。这个技术对代码生成这类确定性强的任务效果特别好。缓存对常见问题缓存回答避免重复推理。可以用Redis做缓存层命中缓存直接返回延迟从秒级降到毫秒级。流式输出不等全部生成完再返回而是生成一个token返回一个。用户感知的延迟大幅降低虽然总生成时间没变但体验好很多。我在实际项目里把流式输出和缓存都用上了用户侧的首字延迟从2秒降到200毫秒以内体感提升非常明显。6. 常见问题与排查实录6.1 模型加载与推理报错问题一CUDA out of memory这是最常见的问题。原因可能是模型太大、序列太长、批次太大。解决办法用量化版本、减小max_model_len、减小batch_size、开启梯度检查点。我一般先用nvidia-smi看显存占用确认是模型本身占太多还是中间激活值占太多。问题二RuntimeError: expected scalar type Half but found Float数据类型不匹配。检查模型加载时的torch_dtype和输入数据的类型是否一致。有时候是某些自定义层没有正确转换类型需要手动.half()。问题三Token indices sequence length is longer than the specified maximum输入序列超过模型最大长度。DeepSeek一般支持4096或8192的上下文超长需要截断或分段处理。我通常会在tokenizer阶段就设置truncationTrue和max_length。6.2 微调训练问题问题一Loss不下降可能原因学习率太小、数据有问题、模型冻结了不该冻结的层。我一般先检查数据格式对不对再用一个极小的学习率跑几步看loss有没有变化。如果loss完全不动多半是数据或模型配置的问题。问题二Loss震荡严重学习率太大或批次太小。降低学习率、增大批次大小、增加warmup步数都能缓解。我试过把学习率从5e-4降到1e-4震荡明显减轻。问题三过拟合训练集loss持续下降但验证集loss上升。解决办法增加数据量、增大dropout、减少训练轮数、加正则化。早停early stopping也是个好办法验证集loss连续几轮不降就停。6.3 部署与服务问题问题一并发请求时响应变慢GPU是串行处理请求的并发高了自然排队。解决办法用vLLM的连续批处理、增加GPU数量、上量化模型。如果业务允许还可以做请求队列和限流。问题二长文本生成中断可能是max_tokens设太小或者触发了某些停止条件。检查生成参数确保max_tokens足够大停止词设置合理。问题三输出重复内容生成参数设置不当。降低temperature、调整top_p、加重复惩罚repetition_penalty。我一般设repetition_penalty1.1能有效减少重复。6.4 常见问题速查表问题现象可能原因排查方向解决办法显存溢出模型太大/序列太长看nvidia-smi显存占用量化、减小批次、缩短序列加载报错版本不匹配检查transformers和torch版本统一版本组合Loss不降学习率/数据问题检查数据格式和loss曲线调学习率、清洗数据过拟合数据少/训练久对比训练集和验证集loss增数据、加dropout、早停推理慢无批处理/无量化测单次推理延迟vLLM、量化、投机解码输出重复生成参数不当检查temperature和top_p降temperature、加重复惩罚7. 我踩过的坑与实操心得第一个坑是版本兼容性。大模型生态更新太快transformers、torch、CUDA、peft这几个库的版本互相依赖稍不注意就冲突。我的经验是选定一个官方验证过的版本组合然后锁死不要随便升级。升级之前先在虚拟环境里测试确认没问题再动生产环境。第二个坑是数据质量。我一开始图省事直接从网上爬了一堆数据就拿来微调结果模型学了一堆乱七八糟的东西输出质量反而下降了。后来老老实实做数据清洗和筛选用少量高质量数据效果立竿见影。数据这事情真的是“垃圾进垃圾出”。第三个坑是显存估算。我一开始按参数量估算显存7B模型FP16大概14GB觉得24GB显存绰绰有余。结果实际跑起来发现除了模型权重还有KV Cache、中间激活值、梯度等额外开销实际占用远超14GB。后来学乖了显存按参数量的2-3倍估算留足余量。第四个坑是评估方法。我一开始只看loss曲线觉得loss降了就是好。后来发现loss和实际效果不完全对应有些loss很低的模型生成的内容其实很糟糕。现在我会结合自动指标和人工评估确保模型真的有用。第五个坑是部署环境。开发环境跑得好好的一到生产环境就各种问题。可能是CUDA版本不同、驱动版本不同、或者并发压力不同。我的建议是开发环境和生产环境尽量保持一致部署前做压力测试别等上线了才发现问题。最后分享一个实用技巧善用日志。大模型推理和训练过程中日志是最重要的排查工具。我会在关键步骤打日志记录输入输出、耗时、显存占用等信息。出问题的时候日志能帮你快速定位是哪个环节出了错。另外用wandb或tensorboard做训练可视化loss曲线、学习率变化、梯度分布一目了然比看数字直观多了。这份笔记写到这基本上把DeepSeek从了解到上手再到部署的完整链路都覆盖了。大模型这个领域变化很快今天的方法明天可能就过时了但底层的原理和工程思路是相对稳定的。把基础打牢新东西来了上手就快。后续我还会继续折腾多模态、Agent这些方向有新心得再更新。