4、推理基础:使用DeepSeek模型进行文本生成,理解tokenizer、max_length、temperature等参数

说实话,很多人拿到模型第一件事就是直接调API跑生成。但跑出来的结果经常「驴唇不对马嘴」。我刚开始也踩过这个坑——明明模型很强,为什么生成的东西就是不对劲?

后来我才明白,推理不是玄学,是科学。你调教的每一个参数,背后都有它的数学逻辑。今天我们就来拆解DeepSeek推理的底层逻辑。

4.1 Tokenizer:模型的第一道关卡

模型不认识「你好」,它只认识数字。Tokenizer就是那个翻译官——把人类语言转成模型能理解的token ID序列。

核心概念:一个token ≈ 0.75个中文汉字,或者 ≈ 0.3个英文单词。

我在项目中遇到过一个问题:同样的prompt,用不同tokenizer编码,结果完全不同。为什么?因为tokenizer的词汇表决定了模型「看到」什么。

DeepSeek用的是BPE(Byte Pair Encoding)算法。它会把常见词保留为整体,不常见的词拆成子词。举个例子:

# 伪代码示意
text = "深度学习框架"
tokens = tokenizer.encode(text)
print(tokens)  
# 输出: [1256, 3421, 7890, 2345]
# 每个数字对应词汇表里的一个token

decoded = tokenizer.decode(tokens)
print(decoded)  
# 输出: "深度学习框架"

嗯,这里要注意:tokenizer的词汇表是固定的。训练时用什么词汇表,推理时就必须用同一个。我见过有人换了tokenizer,结果模型输出全是乱码——说白了就是编码对不上了。

参数 说明 我的建议
vocab_size 词汇表大小 DeepSeek默认即可,别乱改
add_special_tokens 是否添加特殊标记 一般保持True
max_length 最大token数 下文会细讲

4.2 max_length:给模型画个「边界」

你想想看,如果让模型无限生成,它会怎么样?要么跑出上下文窗口,要么生成一堆废话。max_length就是给模型画个边界。

注意:max_length包括输入+输出。比如你设了512,输入占了200,那输出最多只能生成312个token。

我习惯这样设置:

  • 短文本生成(标题、摘要):max_length = 64-128
  • 中等文本(段落、邮件):max_length = 256-512
  • 长文本(文章、报告):max_length = 1024-2048

曾经有个项目,我设了max_length=2048,结果模型生成了1500个token后开始重复。后来发现是上下文窗口不够用了。所以我的经验是:max_length不要超过模型支持的最大上下文长度的80%

4.3 temperature:控制模型的「创造力」

temperature是我最喜欢的参数。它控制模型输出的随机性——说白了就是「脑洞大小」。

数学本质:temperature是对softmax函数中的logits进行缩放。值越大,概率分布越平滑,模型越「敢想」;值越小,概率分布越尖锐,模型越「保守」。

具体来说:

  • temperature = 0:每次都选概率最高的token,输出确定性强,但容易重复
  • temperature = 0.7:平衡状态,既有创造性又不失连贯性
  • temperature = 1.0:完全按照原始概率分布采样,创造力强但可能跑偏
  • temperature > 1.0:鼓励低概率token,输出可能天马行空

我在项目中遇到过:做客服问答时,temperature设到0.8,结果模型开始「自由发挥」,回答了一些不准确的信息。后来我降到0.3,效果就稳了。

我的经验法则

  • 事实性任务(问答、翻译):temperature = 0.1 - 0.3
  • 创意性任务(写诗、故事):temperature = 0.7 - 0.9
  • 代码生成:temperature = 0.2 - 0.4

4.4 其他关键参数

除了上面三个,还有几个参数我经常调:

参数 作用 推荐值
top_p 核采样,只从累积概率达到p的token中采样 0.9
top_k 只从概率最高的k个token中采样 40-50
repetition_penalty 惩罚重复出现的token 1.0-1.2
do_sample 是否使用采样策略(否则用贪心解码) True

你可能会问:top_p和temperature有什么区别?

简单说:temperature控制整个概率分布的「形状」,而top_p控制从哪些token里选。我一般先调temperature,再微调top_p。

4.5 实战:一个完整的推理流程

光说不练假把式。我们来看一个完整的推理代码:

from transformers import AutoTokenizer, AutoModelForCausalLM

# 加载模型和tokenizer
model_name = "deepseek-ai/deepseek-llm-7b-chat"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

# 准备输入
prompt = "请用一句话解释什么是深度学习"
inputs = tokenizer(prompt, return_tensors="pt")

# 推理参数
outputs = model.generate(
    **inputs,
    max_length=128,           # 总长度限制
    temperature=0.7,          # 创造力控制
    top_p=0.9,                # 核采样
    do_sample=True,           # 启用采样
    repetition_penalty=1.1,   # 防重复
    pad_token_id=tokenizer.eos_token_id
)

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

这段代码我用了不下百次。每次调参,我都会先跑一个基线——temperature=0.7, top_p=0.9,然后根据结果微调。

调试技巧:如果输出太死板,先降temperature;如果输出太散乱,先升temperature。如果出现重复,调repetition_penalty。

4.6 知识体系总览

下面这张图,是我自己总结的推理参数关系图。你看一眼就能明白各个参数在干什么:

DeepSeek推理参数关系图 输入文本 Tokenizer编码 模型推理(生成logits) temperature缩放 top_p / top_k筛选 repetition_penalty 输出文本 max_length控制整个流程的token总数上限

从这张图你能看到:输入文本先经过Tokenizer变成token ID,然后模型生成logits,接着temperature、top_p、repetition_penalty这些参数依次发挥作用,最后输出文本。而max_length就像个「总闸」,控制着整个流程的长度上限。

4.7 避坑指南

最后分享几个我踩过的坑:

  • tokenizer没对齐:我曾经用A模型的tokenizer去加载B模型,结果输出全是乱码。记住:tokenizer必须和模型配套
  • max_length设太小:输出被截断,语义不完整。我习惯设成目标长度的1.5倍。
  • temperature和top_p同时调太高:输出变得极其随机,像喝醉了酒。建议先固定一个,调另一个。
  • 忘记设pad_token_id:有些模型会报错。我一般直接设成eos_token_id。

嗯,这些参数说多不多,说少不少。但只要你理解了每个参数背后的逻辑,调参就不再是玄学。下次跑模型的时候,不妨多花几分钟调调这些参数——你会发现,同样的模型,效果能差出一大截。


专注资料整理