简介:这份资源面向大语言模型零基础学习者与希望系统梳理概念的开发者,围绕LLM入门所需的核心背景知识展开,帮助读者建立从语言模型定义到技术演进的完整认知框架。内容涵盖大语言模型的基本概念、语言模型的概率建模本质与评估指标,并梳理了从基于规则和统计的N-gram模型、神经网络语言模型、预训练语言模型到对话式大模型四个发展阶段,同时讲解N-gram的马尔科夫假设、bigram与trigram参数计算、数据稀疏与OOV等典型问题,以及神经网络语言模型的输入输出结构与优缺点。资源包共1个PDF文件,约3.24MB,便于在电脑或移动端随时翻阅,适合作为入门阶段的系统笔记与复习提纲。目前已有129人学习,适合想快速理解LLM来龙去脉、为后续深入学习打基础的读者参考。
1. 大语言模型入门的基础知识:从一次翻车的微调说起
很多新手第一次碰大语言模型,都是被“微调”两个字带进来的。我见过一个典型场景:某开发者拿到一份开源权重,兴冲冲跑了一遍全参数微调,结果显存直接爆掉,训练脚本连第一个 step 都没走完。问题不在代码,而在他对“大语言模型入门的基础知识”这件事的理解顺序反了——先学怎么调,再学它是什么,最后才补数据怎么处理。正确的顺序应该倒过来:先搞清楚 token、上下文窗口、参数量、显存占用这几件事的因果关系,再决定是走推理、微调还是 RAG。这篇笔记面向的是想真正把模型跑起来、而不是只停留在概念层面的从业者。我会按“先立住理论、再动手复现”的路径,把入门阶段最容易踩的坑和最小可跑通的命令讲清楚,让你看完能自己判断一个模型能不能在你的机器上跑、该怎么跑。
2. 先把 token、上下文和显存这三件事算明白
大语言模型入门最容易被跳过的一步,是算账。不算账就上手,结果就是显存爆、速度慢、效果差三连。这一章不讲模型结构,只讲三个决定你能不能跑起来的量:token 怎么数、上下文窗口怎么影响显存、参数量和显存之间是什么关系。
2.1 token 不是字,也不是词
token 是模型处理文本的最小单位,但它既不是字符也不是单词。英文里一个 token 大约是 0.75 个单词,中文里一个汉字通常对应 1 到 2 个 token,具体取决于分词器。这件事直接影响你的成本估算和上下文长度判断。很多人以为“上下文 8k”就是能塞 8000 个汉字,实际可能只有 4000 到 6000 个汉字,剩下的被分词器吃掉了。
用 HuggingFace 的 tokenizer 数一下最直接:
from transformers import AutoTokenizer # 加载分词器,这里用常见的开源模型结构举例 tokenizer = AutoTokenizer.from_pretrained("your-model-path") text = "大语言模型入门的基础知识,先搞清楚 token 怎么数。" tokens = tokenizer.encode(text) print("token 数量:", len(tokens)) print("token 内容:", tokenizer.convert_ids_to_tokens(tokens))这段代码的逻辑是:encode把文本转成 token id 序列,convert_ids_to_tokens把 id 还原成可读的 token 片段。参数上,pretrained填你本地的模型路径或模型标识,不要填不存在的路径。跑完之后你会看到中文被切成什么样——有些词是一个 token,有些被拆成两三个。这个结果决定了你后面设置max_length时该留多少余量。
提示:不同模型的分词器不一样,同一个句子在不同模型下的 token 数可能差 30% 以上。换模型时一定要重新数一遍。
2.2 上下文窗口和显存的关系
上下文窗口(context window)指的是模型一次能处理的最大 token 数。它和显存的关系不是线性的,而是近似平方关系——因为注意力机制的计算量随序列长度平方增长。这意味着你把上下文从 2k 拉到 8k,显存占用可能翻好几倍,而不是翻四倍那么简单。
实际估算时,推理阶段的显存大致由三部分组成:模型权重、KV Cache、激活值。模型权重是固定的,KV Cache 随上下文长度线性增长,激活值在推理时占比很小。所以推理时真正卡你的是 KV Cache。
一个粗略的估算公式:
| 项目 | 估算方式 | 说明 |
|---|---|---|
| 模型权重 | 参数量 × 精度字节数 | fp16 是 2 字节,int8 是 1 字节 |
| KV Cache | 2 × 层数 × 头数 × 头维度 × 序列长度 × 精度字节数 | 每层每头都要存 key 和 value |
| 激活值 | 通常几百 MB | 推理时占比小,训练时占比大 |
以 7B 模型 fp16 为例,权重约 14GB。如果上下文开到 4096,KV Cache 可能再吃 2 到 4GB。所以一张 24GB 的卡跑 7B 推理是够的,但跑 13B 就很紧张。
2.3 参数量和显存:训练比推理狠得多
推理时显存 ≈ 权重 + KV Cache。训练时显存 ≈ 权重 + 梯度 + 优化器状态 + 激活值。全参数微调时,梯度占一份权重,Adam 优化器状态占两份权重,加起来就是四倍。7B 模型 fp16 全参数微调,光权重和优化器状态就要 14GB × 4 = 56GB,还没算激活值。这就是为什么单卡全参微调基本不可行。
常见做法是走 LoRA 或 QLoRA。LoRA 只训练低秩矩阵,参数量降到原来的百分之几,显存需求大幅下降。QLoRA 再把基础模型量化到 4bit,进一步压缩。下面是一个 LoRA 配置的示例:
from peft import LoraConfig, get_peft_model # LoRA 配置:只训练低秩矩阵,冻结原模型权重 lora_config = LoraConfig( r=8, # 低秩矩阵的秩,越大容量越强但显存越高 lora_alpha=16, # 缩放系数,通常设为 r 的两倍 target_modules=["q_proj", "v_proj"], # 作用在注意力的 query 和 value 投影上 lora_dropout=0.05, # 防止过拟合 bias="none", # 不训练偏置项 task_type="CAUSAL_LM" # 因果语言模型任务 ) model = get_peft_model(base_model, lora_config) model.print_trainable_parameters()r是最关键的参数,8 到 16 是入门常用范围,再大收益递减。target_modules决定把 LoRA 加在哪些层上,只加q_proj和v_proj是最省显存的保守做法,效果不够再考虑加k_proj和o_proj。lora_alpha控制 LoRA 输出的缩放,经验值是r的两倍。跑完print_trainable_parameters你会看到可训练参数占比,通常在 0.1% 到 1% 之间。
3. 用最小命令跑通一次本地推理
理论算完,下一步是让它真的跑起来。这一章给出一条从环境准备到出结果的最短路径,不涉及训练,只做推理。跑通之后再谈微调,心里才有底。
3.1 环境准备:版本对齐比装什么更重要
新手翻车最多的地方不是代码写错,而是版本不匹配。transformers、torch、accelerate这三个包的版本要互相对得上,否则会出现各种奇怪的报错。我一般会先建一个干净的虚拟环境,再按固定顺序装。
# 创建虚拟环境 python -m venv llm-env source llm-env/bin/activate # 先装 torch,根据你的 CUDA 版本选对应命令 pip install torch --index-url https://download.pytorch.org/whl/cu121 # 再装 transformers 和 accelerate pip install transformers accelerate sentencepiece # 验证安装 python -c "import torch; print(torch.__version__, torch.cuda.is_available())"顺序很重要:先装 torch,再装 transformers。反过来装的话,pip 可能会拉一个 CPU 版的 torch 覆盖掉 GPU 版。最后那行验证命令会输出 torch 版本和 CUDA 是否可用,如果cuda.is_available()是 False,后面所有推理都会跑在 CPU 上,慢到无法接受。
注意:不要盲目
pip install -U把所有包升到最新。最新版之间经常有兼容问题,入门阶段用稳定组合比追新更重要。
3.2 加载模型并生成第一段文本
环境好了之后,加载模型做一次生成。这里用pipeline是最省事的入口,它把分词、推理、解码都封装好了。
from transformers import pipeline # 加载文本生成 pipeline generator = pipeline( "text-generation", model="your-model-path", # 本地模型路径 device_map="auto", # 自动分配到可用显卡 torch_dtype="auto" # 自动选择精度 ) # 生成文本 result = generator( "大语言模型入门的基础知识包括", max_new_tokens=128, # 最多生成 128 个新 token do_sample=True, # 启用采样,输出更多样 temperature=0.7, # 温度,越高越随机 top_p=0.9 # 核采样,控制候选范围 ) print(result[0]["generated_text"])device_map="auto"让 accelerate 自动把模型层分配到显卡和内存上,单卡或多卡都能用。torch_dtype="auto"会根据模型配置自动选 fp16 或 bf16。生成参数里,max_new_tokens控制输出长度,不要设太大,否则显存会随生成过程持续增长。temperature和top_p是采样策略,入门阶段用 0.7 和 0.9 是比较稳的组合,想要确定性输出就把do_sample设为 False。
跑通这一步,你会看到模型接着你的开头往下写。如果输出是乱码或重复,先检查分词器是否和模型匹配,再检查精度设置。
3.3 用命令行快速验证模型能不能跑
有时候你不想写脚本,只想快速确认模型文件完不完整、能不能加载。用transformers自带的命令行工具可以省掉写代码的步骤。
# 用命令行做一次简单生成 python -m transformers.models.auto.modeling_auto \ --model_name_or_path your-model-path \ --prompt "大语言模型入门" \ --max_new_tokens 64这条命令的实际作用是触发模型加载和一次前向推理。如果模型文件缺失或配置损坏,会在加载阶段就报错,比在完整脚本里排查更快。参数上,model_name_or_path指向本地路径,prompt是输入文本,max_new_tokens控制输出长度。这个方式适合在部署前做冒烟测试。
4. 避坑:入门阶段最常见的五类翻车
这一章集中讲踩坑记录,每条按现象、原因、解决来写。这些都是我在实际环境里反复见到的,不是理论推演。
4.1 显存明明够却报 OOM
现象:显卡是 24GB,模型权重只有 14GB,但一加载就报 CUDA out of memory。
原因通常有三个:一是torch_dtype没设,模型默认以 fp32 加载,显存直接翻倍;二是device_map没设,模型全部挤在一张卡上;三是加载时同时保留了原始权重和转换后的权重,峰值显存翻倍。
解决:显式设置torch_dtype=torch.float16和device_map="auto"。如果还是不够,用load_in_8bit=True做 8bit 量化加载。加载完成后可以用torch.cuda.memory_allocated()看实际占用,而不是只看任务管理器。
4.2 生成结果重复或胡言乱语
现象:模型输出的文本不断重复同一句话,或者完全不通顺。
原因:采样参数设置不当是最常见的。temperature太低会导致输出退化成贪心解码,容易重复;top_p设得太小会限制候选范围,导致语义断裂。另一个原因是分词器和模型不匹配,token id 对不上,解码出来就是乱码。
解决:先把do_sample=True、temperature=0.7、top_p=0.9作为基线,再根据效果微调。如果还是乱,检查tokenizer是否和model来自同一个路径。用tokenizer.decode(tokenizer.encode("测试"))看能不能还原,不能还原就是分词器问题。
4.3 微调后效果反而变差
现象:LoRA 微调跑完了,loss 也降了,但推理时模型回答质量下降,甚至丢失了原有能力。
原因:学习率太高或训练轮数太多,导致模型过拟合到小数据集上,把原有知识覆盖了。另一个原因是训练数据和推理时的 prompt 格式不一致,模型学到的模式和实际使用对不上。
解决:LoRA 的学习率通常设在 1e-4 到 3e-4 之间,比全参微调高一个量级,但不要超过 5e-4。训练轮数控制在 1 到 3 轮,看验证集 loss 不再下降就停。最重要的是保证训练和推理用同一套 prompt 模板,包括系统提示和分隔符。
4.4 推理速度慢到无法接受
现象:生成 100 个 token 要几十秒,完全没法交互。
原因:模型跑在 CPU 上,或者没有用 KV Cache,或者 batch size 设成了 1 但序列很长。还有一种情况是用了do_sample=True但没设max_new_tokens,模型一直生成到上下文上限。
解决:先确认torch.cuda.is_available()是 True。然后确认生成时用了use_cache=True(默认是开的)。如果还是慢,考虑用量化版本或更小的模型。交互场景下,7B 模型在消费级显卡上生成 100 token 应该在几秒内,超过 10 秒就要查原因。
4.5 中文输出夹杂英文或符号
现象:模型回答中文问题时,中间突然冒出英文单词或奇怪符号。
原因:训练数据里中英文混合比例高,模型没有严格的语言控制。另一个原因是 prompt 本身没有明确指定输出语言。
解决:在 prompt 里显式写“请用中文回答”,或者在系统提示里固定语言。如果还是夹杂,可以在生成参数里加repetition_penalty=1.1抑制重复和异常 token。根本解法是选一个中文能力更强的基座模型,而不是在解码阶段硬压。
5. 进阶:用评估集判断模型到底行不行
跑通推理和微调之后,下一个问题是:怎么知道模型好不好?靠肉眼看几条输出是不够的,你需要一个固定的评估集和一套可重复的评估流程。这一章讲一个最小可用的评估方法,不依赖外部平台,本地就能跑。
5.1 构造一个 20 条的小评估集
评估集不需要大,但要有代表性。入门阶段,20 条覆盖不同任务类型的样本就够你发现大部分问题。我一般会按下面这个结构来组织:
| 任务类型 | 样本数 | 示例问题 |
|---|---|---|
| 事实问答 | 5 | 某个概念的定义是什么 |
| 推理判断 | 5 | 给条件判断结论是否成立 |
| 格式遵循 | 5 | 要求输出 JSON 或固定格式 |
| 拒答边界 | 5 | 问一个不该回答的问题,看是否拒绝 |
把这 20 条写成一个 JSON 文件,每条包含question和reference两个字段。reference是你期望的输出,不要求逐字匹配,但要有明确的判断标准。
5.2 用脚本批量跑评估并打分
评估脚本的核心逻辑是:遍历评估集,逐条生成,然后按规则打分。打分可以用精确匹配、关键词命中或人工复核,入门阶段用关键词命中就够。
import json from transformers import pipeline # 加载模型 generator = pipeline("text-generation", model="your-model-path", device_map="auto") # 读取评估集 with open("eval_set.json", "r", encoding="utf-8") as f: eval_set = json.load(f) results = [] for item in eval_set: output = generator( item["question"], max_new_tokens=128, do_sample=False, # 评估时关闭采样,保证可复现 temperature=1.0 )[0]["generated_text"] # 简单关键词命中判断 hit = item["reference"] in output results.append({"question": item["question"], "hit": hit, "output": output}) # 统计命中率 hit_rate = sum(r["hit"] for r in results) / len(results) print(f"命中率: {hit_rate:.2%}") # 输出未命中的样本,便于分析 for r in results: if not r["hit"]: print("未命中:", r["question"]) print("实际输出:", r["output"][:200])这段代码的关键点是do_sample=False,评估时必须关闭采样,否则每次结果不一样,没法比较。temperature在关闭采样时不生效,但保留参数不影响。命中率只是粗指标,真正有价值的是未命中样本的分析——看模型是理解错了、格式错了还是拒答了,对应不同的改进方向。
5.3 对比两个版本的模型
有了评估脚本,你就可以做 A/B 对比。比如微调前后的模型、不同量化精度的模型、不同 prompt 模板的效果。做法很简单:把model参数换掉,跑同一套评估集,对比命中率。
我一般会固定三件事:评估集不变、生成参数不变、打分规则不变。只改一个变量,才能知道效果变化是哪个因素带来的。如果一次改多个,命中率涨了也不知道该归功于谁。
提示:评估集不要用来调参。调参用验证集,评估集只在最后判断时用一次。否则你是在对评估集过拟合。
5.4 一个我反复用的习惯
每次换模型或改配置,先跑 5 条快速冒烟,确认没有报错和明显异常,再跑完整 20 条。这个习惯帮我省了很多时间——很多问题在前 5 条就能暴露,不用等全量跑完。另外,评估结果一定要存下来,按日期和配置命名,过一个月回头看,你会感谢自己留了这些记录。
入门大语言模型,最怕的不是不懂原理,而是不动手。先把 token 数清楚,再把最小推理跑通,然后用评估集建立反馈闭环,这三步走完,你就算真正入门了。希望帮到你。
本文还有配套的精品资源,点击获取