<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LoRA on Khari Z's LogBook</title><link>https://n571e.github.io/tags/lora/</link><description>Recent content in LoRA on Khari Z's LogBook</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 21 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://n571e.github.io/tags/lora/index.xml" rel="self" type="application/rss+xml"/><item><title>用 Transformers 跑通 LLM 训练流程：预训练、SFT 和 LoRA</title><link>https://n571e.github.io/p/happy-llm-transformers-training-practice/</link><pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate><guid>https://n571e.github.io/p/happy-llm-transformers-training-practice/</guid><description>&lt;img src="https://n571e.github.io/" alt="Featured image of post 用 Transformers 跑通 LLM 训练流程：预训练、SFT 和 LoRA" /&gt;&lt;p&gt;第六章开始贴近工程实践：用 &lt;code&gt;Transformers + datasets + Trainer + DeepSpeed + peft&lt;/code&gt; 这套生态把 LLM 训练流程串起来。&lt;/p&gt;&#10;&lt;p&gt;这一章可以整理成一句话：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;模型怎么初始化、数据怎么整理进 Trainer、预训练和 SFT 的标签怎么分开、资源不够时怎么换成 LoRA，这四件事就是第六章的主线。&lt;/strong&gt;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;这篇文章按训练流程整理，方便以后回查每一步对应的框架、数据格式和参数。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="一先把第六章的训练流程整理成链路"&gt;&lt;a href="#%e4%b8%80%e5%85%88%e6%8a%8a%e7%ac%ac%e5%85%ad%e7%ab%a0%e7%9a%84%e8%ae%ad%e7%bb%83%e6%b5%81%e7%a8%8b%e6%95%b4%e7%90%86%e6%88%90%e9%93%be%e8%b7%af" class="header-anchor"&gt;&lt;/a&gt;一、先把第六章的训练流程整理成链路&#10;&lt;/h2&gt;&lt;p&gt;从工程视角看，第六章讲的是这样一条链路：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;模型配置与 tokenizer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 预训练数据处理&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; TrainingArguments + Trainer&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; DeepSpeed 分布式启动&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; SFT 数据构造&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; LoRA / peft 高效微调&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;这条链路要看的不是框架名字有多熟，而是每个组件承担哪一层职责：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;Transformers&lt;/code&gt; 负责把模型和训练流程抽象成统一接口&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;datasets&lt;/code&gt; 负责把原始文本或对话数据整理成模型可训练的张量格式&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;Trainer&lt;/code&gt; 负责承接训练参数、数据集、保存和日志等通用逻辑&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;DeepSpeed&lt;/code&gt; 负责把训练推到多卡和更大规模上&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;peft&lt;/code&gt; 负责在资源受限时把全量微调切成 LoRA 这种高效微调路径&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;复习锚点：&lt;code&gt;Transformers&lt;/code&gt; 管模型接口，&lt;code&gt;datasets&lt;/code&gt; 管数据流水线，&lt;code&gt;Trainer&lt;/code&gt; 管训练脚手架，&lt;code&gt;DeepSpeed&lt;/code&gt; 管大规模训练，&lt;code&gt;peft&lt;/code&gt; 管高效微调。&lt;/p&gt;&#10;&lt;div align="center"&gt;&#10; &lt;img src="https://raw.githubusercontent.com/datawhalechina/happy-llm/main/docs/images/6-images/1-2.png" alt="Hugging Face Transformers 模型社区" width="90%" /&gt;&#10; &lt;p&gt;图：第六章借助 Hugging Face 生态把模型、数据集与训练框架串到了一起&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="二第一步先把模型和-tokenizer-初始化起来"&gt;&lt;a href="#%e4%ba%8c%e7%ac%ac%e4%b8%80%e6%ad%a5%e5%85%88%e6%8a%8a%e6%a8%a1%e5%9e%8b%e5%92%8c-tokenizer-%e5%88%9d%e5%a7%8b%e5%8c%96%e8%b5%b7%e6%9d%a5" class="header-anchor"&gt;&lt;/a&gt;二、第一步：先把模型和 tokenizer 初始化起来&#10;&lt;/h2&gt;&lt;p&gt;模型和 tokenizer 初始化负责明确两件事：训练哪个模型，以及文本如何进入这个模型。&lt;/p&gt;&#10;&lt;p&gt;第六章选的是 &lt;code&gt;Qwen-2.5-1.5B&lt;/code&gt;。&lt;code&gt;Transformers&lt;/code&gt; 里有两种常见初始化方式：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;基于配置从零初始化一个模型&lt;/li&gt;&#10;&lt;li&gt;基于已有权重加载一个预训练模型&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;对应到代码里，主干大概就是下面这样：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;span class="lnt"&gt;6&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust_remote_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;如果要直接继承已有权重，通常会改成：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust_remote_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="21-auto-这套接口是在接住模型族差异"&gt;&lt;a href="#21-auto-%e8%bf%99%e5%a5%97%e6%8e%a5%e5%8f%a3%e6%98%af%e5%9c%a8%e6%8e%a5%e4%bd%8f%e6%a8%a1%e5%9e%8b%e6%97%8f%e5%b7%ae%e5%bc%82" class="header-anchor"&gt;&lt;/a&gt;2.1 &lt;code&gt;Auto*&lt;/code&gt; 这套接口是在接住“模型族差异”&#10;&lt;/h3&gt;&lt;p&gt;只要配置和权重兼容，&lt;code&gt;AutoConfig&lt;/code&gt;、&lt;code&gt;AutoModelForCausalLM&lt;/code&gt;、&lt;code&gt;AutoTokenizer&lt;/code&gt; 就能把很多模型族差异统一到同一套接口下。这样训练脚本可以把重心放在数据、参数和流程上。&lt;/p&gt;&#10;&lt;h3 id="22-训练阶段不同模型加载方式可能不同但-tokenizer-契约不能乱"&gt;&lt;a href="#22-%e8%ae%ad%e7%bb%83%e9%98%b6%e6%ae%b5%e4%b8%8d%e5%90%8c%e6%a8%a1%e5%9e%8b%e5%8a%a0%e8%bd%bd%e6%96%b9%e5%bc%8f%e5%8f%af%e8%83%bd%e4%b8%8d%e5%90%8c%e4%bd%86-tokenizer-%e5%a5%91%e7%ba%a6%e4%b8%8d%e8%83%bd%e4%b9%b1" class="header-anchor"&gt;&lt;/a&gt;2.2 训练阶段不同，模型加载方式可能不同，但 tokenizer 契约不能乱&#10;&lt;/h3&gt;&lt;p&gt;无论是 Pretrain 还是 SFT，tokenizer 都是一套输入协议。它定义的是：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;词表怎么映射&lt;/li&gt;&#10;&lt;li&gt;特殊 token 怎么表示&lt;/li&gt;&#10;&lt;li&gt;对话边界怎么标记&lt;/li&gt;&#10;&lt;li&gt;padding 和 EOS 怎么约定&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;尤其到了后面的 SFT，这个 tokenizer 契约会直接决定 &lt;code&gt;chat template&lt;/code&gt; 和 &lt;code&gt;labels&lt;/code&gt; 的构造方式。&lt;/p&gt;&#10;&lt;p&gt;复习锚点：模型初始化把后续训练步骤接到统一的 Hugging Face 模型接口上；tokenizer 则规定了输入协议。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="三第二步把预训练数据整理成-trainer-能直接吃的样子"&gt;&lt;a href="#%e4%b8%89%e7%ac%ac%e4%ba%8c%e6%ad%a5%e6%8a%8a%e9%a2%84%e8%ae%ad%e7%bb%83%e6%95%b0%e6%8d%ae%e6%95%b4%e7%90%86%e6%88%90-trainer-%e8%83%bd%e7%9b%b4%e6%8e%a5%e5%90%83%e7%9a%84%e6%a0%b7%e5%ad%90" class="header-anchor"&gt;&lt;/a&gt;三、第二步：把预训练数据整理成 Trainer 能直接吃的样子&#10;&lt;/h2&gt;&lt;p&gt;预训练数据处理负责把原始文本变成 CLM 训练样本。&lt;/p&gt;&#10;&lt;p&gt;第六章的预训练流程是 Causal Language Modeling，也就是预测下一个 token。进入 &lt;code&gt;datasets&lt;/code&gt; 生态后，数据预处理通常写成流水线：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;用 &lt;code&gt;load_dataset&lt;/code&gt; 读入原始 JSON/JSONL&lt;/li&gt;&#10;&lt;li&gt;用 tokenizer 把文本转成 token IDs&lt;/li&gt;&#10;&lt;li&gt;把多个文本段拼起来，切成固定长度 block&lt;/li&gt;&#10;&lt;li&gt;令 &lt;code&gt;labels = input_ids.copy()&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;这段代码骨架最值得回看：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;span class="lnt"&gt;21&#10;&lt;/span&gt;&lt;span class="lnt"&gt;22&#10;&lt;/span&gt;&lt;span class="lnt"&gt;23&#10;&lt;/span&gt;&lt;span class="lnt"&gt;24&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dataset&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;itertools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data_files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;train_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tokenize_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tokenized_datasets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ds&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tokenize_function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;batched&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;remove_columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;column_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;group_texts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;concatenated_examples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;total_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;concatenated_examples&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;examples&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;total_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_length&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;concatenated_examples&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;labels&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;input_ids&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="31-labels--input_idscopy-是预训练阶段的记忆锚点"&gt;&lt;a href="#31-labels--input_idscopy-%e6%98%af%e9%a2%84%e8%ae%ad%e7%bb%83%e9%98%b6%e6%ae%b5%e7%9a%84%e8%ae%b0%e5%bf%86%e9%94%9a%e7%82%b9" class="header-anchor"&gt;&lt;/a&gt;3.1 &lt;code&gt;labels = input_ids.copy()&lt;/code&gt; 是预训练阶段的记忆锚点&#10;&lt;/h3&gt;&lt;p&gt;这句代码明确了：&lt;strong&gt;Pretrain 阶段的监督目标就是整段文本自身。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;也就是说，预训练数据的重点不在“问题-答案”格式，而在：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;先把文本稳定 tokenize&lt;/li&gt;&#10;&lt;li&gt;再拼接成足够长的训练块&lt;/li&gt;&#10;&lt;li&gt;让每个块都作为一个 CLM 样本参与训练&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;code&gt;group_texts&lt;/code&gt; 的作用是把多个文本片段拼接后切成固定长度 block。预训练更关注吞吐和有效 token 利用率，而不是保留每段原始文本的天然边界。固定长度 block 可以减少 padding 浪费。&lt;/p&gt;&#10;&lt;h3 id="32-预训练数据处理是在整理训练协议"&gt;&lt;a href="#32-%e9%a2%84%e8%ae%ad%e7%bb%83%e6%95%b0%e6%8d%ae%e5%a4%84%e7%90%86%e6%98%af%e5%9c%a8%e6%95%b4%e7%90%86%e8%ae%ad%e7%bb%83%e5%8d%8f%e8%ae%ae" class="header-anchor"&gt;&lt;/a&gt;3.2 预训练数据处理是在整理训练协议&#10;&lt;/h3&gt;&lt;p&gt;进入框架训练后，数据处理要回答四个问题：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;block 多长&lt;/li&gt;&#10;&lt;li&gt;是否拼接多个样本&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;labels&lt;/code&gt; 怎样和 &lt;code&gt;input_ids&lt;/code&gt; 对齐&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;attention_mask&lt;/code&gt; 由谁生成&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这些细节表面上是数据预处理，实际上已经在决定模型训练看到的输入分布。&lt;/p&gt;&#10;&lt;p&gt;复习锚点：预训练数据处理就是把“文本 -&amp;gt; token -&amp;gt; block -&amp;gt; labels”这条链放进 &lt;code&gt;datasets.map&lt;/code&gt;。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="四第三步用-trainer-把训练参数日志和保存逻辑接起来"&gt;&lt;a href="#%e5%9b%9b%e7%ac%ac%e4%b8%89%e6%ad%a5%e7%94%a8-trainer-%e6%8a%8a%e8%ae%ad%e7%bb%83%e5%8f%82%e6%95%b0%e6%97%a5%e5%bf%97%e5%92%8c%e4%bf%9d%e5%ad%98%e9%80%bb%e8%be%91%e6%8e%a5%e8%b5%b7%e6%9d%a5" class="header-anchor"&gt;&lt;/a&gt;四、第三步：用 Trainer 把训练参数、日志和保存逻辑接起来&#10;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;Trainer&lt;/code&gt; 这一层负责把模型、数据和训练参数装进一个可运行的训练器。&lt;/p&gt;&#10;&lt;p&gt;第六章用的是 &lt;code&gt;TrainingArguments + Trainer&lt;/code&gt; 这条最典型的 &lt;code&gt;Transformers&lt;/code&gt; 路线。骨架很简单：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;span class="lnt"&gt;14&#10;&lt;/span&gt;&lt;span class="lnt"&gt;15&#10;&lt;/span&gt;&lt;span class="lnt"&gt;16&#10;&lt;/span&gt;&lt;span class="lnt"&gt;17&#10;&lt;/span&gt;&lt;span class="lnt"&gt;18&#10;&lt;/span&gt;&lt;span class="lnt"&gt;19&#10;&lt;/span&gt;&lt;span class="lnt"&gt;20&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrainingArguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Trainer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default_data_collator&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;training_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TrainingArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;output_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;output&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;per_device_train_batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;gradient_accumulation_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;logging_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;num_train_epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;save_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1e-4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;gradient_checkpointing&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;trainer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Trainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;training_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;train_dataset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;train_dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data_collator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;default_data_collator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="41-trainingarguments-负责的是训练策略的通用外壳"&gt;&lt;a href="#41-trainingarguments-%e8%b4%9f%e8%b4%a3%e7%9a%84%e6%98%af%e8%ae%ad%e7%bb%83%e7%ad%96%e7%95%a5%e7%9a%84%e9%80%9a%e7%94%a8%e5%a4%96%e5%a3%b3" class="header-anchor"&gt;&lt;/a&gt;4.1 &lt;code&gt;TrainingArguments&lt;/code&gt; 负责的是“训练策略的通用外壳”&#10;&lt;/h3&gt;&lt;p&gt;比如：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;batch size&lt;/li&gt;&#10;&lt;li&gt;梯度累积&lt;/li&gt;&#10;&lt;li&gt;学习率&lt;/li&gt;&#10;&lt;li&gt;日志频率&lt;/li&gt;&#10;&lt;li&gt;保存策略&lt;/li&gt;&#10;&lt;li&gt;gradient checkpointing&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这些参数放进 &lt;code&gt;TrainingArguments&lt;/code&gt; 后，模型逻辑、数据逻辑和训练策略开始分层。&lt;/p&gt;&#10;&lt;h3 id="42-trainer-统一的是训练脚手架"&gt;&lt;a href="#42-trainer-%e7%bb%9f%e4%b8%80%e7%9a%84%e6%98%af%e8%ae%ad%e7%bb%83%e8%84%9a%e6%89%8b%e6%9e%b6" class="header-anchor"&gt;&lt;/a&gt;4.2 &lt;code&gt;Trainer&lt;/code&gt; 统一的是训练脚手架&#10;&lt;/h3&gt;&lt;p&gt;到了这里，很多通用工作都不需要自己再反复写：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;前向和反向训练循环&lt;/li&gt;&#10;&lt;li&gt;日志打印&lt;/li&gt;&#10;&lt;li&gt;checkpoint 保存&lt;/li&gt;&#10;&lt;li&gt;tokenizer/data collator 接入&lt;/li&gt;&#10;&lt;li&gt;分布式训练接口对接&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;复习锚点：&lt;code&gt;Trainer&lt;/code&gt; 的价值不是替代理解，而是把已经理解的训练骨架抽成可复用模板。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="五第四步从-notebook-走向可长期运行的-deepspeed-训练脚本"&gt;&lt;a href="#%e4%ba%94%e7%ac%ac%e5%9b%9b%e6%ad%a5%e4%bb%8e-notebook-%e8%b5%b0%e5%90%91%e5%8f%af%e9%95%bf%e6%9c%9f%e8%bf%90%e8%a1%8c%e7%9a%84-deepspeed-%e8%ae%ad%e7%bb%83%e8%84%9a%e6%9c%ac" class="header-anchor"&gt;&lt;/a&gt;五、第四步：从 notebook 走向可长期运行的 DeepSpeed 训练脚本&#10;&lt;/h2&gt;&lt;p&gt;前几节解决“如何用框架表达训练流程”，DeepSpeed 解决“如何把训练推进到多卡和更大模型规模”。&lt;/p&gt;&#10;&lt;p&gt;第六章进一步给出了：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;pretrain.py&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;finetune.py&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;pretrain.sh&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;finetune.sh&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ds_config_zero2.json&lt;/code&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这说明训练流程已经从“演示思路”切换到了“脚本化运行”。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;pretrain.sh&lt;/code&gt; 的典型启动方式大致是这样：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;deepspeed pretrain.py &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --config_name autodl-tmp/qwen-1.5b &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --tokenizer_name autodl-tmp/qwen-1.5b &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --train_files autodl-tmp/dataset/pretrain_data/xxx.jsonl &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --per_device_train_batch_size &lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --gradient_accumulation_steps &lt;span class="m"&gt;4&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output_dir autodl-tmp/output/pretrain &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --learning_rate 1e-4 &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --num_train_epochs &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --block_size &lt;span class="m"&gt;2048&lt;/span&gt; &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --bf16 &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --gradient_checkpointing &lt;span class="se"&gt;\&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --deepspeed ./ds_config_zero2.json&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="51-deepspeed-在这一章里主要承担两件事"&gt;&lt;a href="#51-deepspeed-%e5%9c%a8%e8%bf%99%e4%b8%80%e7%ab%a0%e9%87%8c%e4%b8%bb%e8%a6%81%e6%89%bf%e6%8b%85%e4%b8%a4%e4%bb%b6%e4%ba%8b" class="header-anchor"&gt;&lt;/a&gt;5.1 DeepSpeed 在这一章里主要承担两件事&#10;&lt;/h3&gt;&lt;p&gt;第一，让训练自然走向多卡。第二，通过 ZeRO 等策略降低显存压力。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;ds_config_zero2.json&lt;/code&gt; 里最该看的关键词是 &lt;code&gt;zero_optimization.stage = 2&lt;/code&gt;。这表示采用 &lt;code&gt;ZeRO-2&lt;/code&gt;，主要优化优化器状态和梯度的存储开销。&lt;/p&gt;&#10;&lt;h3 id="52-从-notebook-到脚本增加的是工程外壳"&gt;&lt;a href="#52-%e4%bb%8e-notebook-%e5%88%b0%e8%84%9a%e6%9c%ac%e5%a2%9e%e5%8a%a0%e7%9a%84%e6%98%af%e5%b7%a5%e7%a8%8b%e5%a4%96%e5%a3%b3" class="header-anchor"&gt;&lt;/a&gt;5.2 从 notebook 到脚本，增加的是工程外壳&#10;&lt;/h3&gt;&lt;p&gt;比如在 &lt;code&gt;pretrain.py&lt;/code&gt; 里，第六章补上了很多真实训练需要的东西：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;HfArgumentParser&lt;/code&gt; 解析命令行参数&lt;/li&gt;&#10;&lt;li&gt;checkpoint 恢复&lt;/li&gt;&#10;&lt;li&gt;主进程数据预处理&lt;/li&gt;&#10;&lt;li&gt;SwanLab 日志&lt;/li&gt;&#10;&lt;li&gt;shell 层统一管理训练超参&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这时可以区分两类内容：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;notebook 负责验证思路&lt;/li&gt;&#10;&lt;li&gt;脚本负责承接长时间训练&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;复习锚点：DeepSpeed 和 shell 脚本把训练从教学演示推进到可长期运行、可恢复、可记录的工程流程。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="六第五步进入-sft-后差异主要在数据构造"&gt;&lt;a href="#%e5%85%ad%e7%ac%ac%e4%ba%94%e6%ad%a5%e8%bf%9b%e5%85%a5-sft-%e5%90%8e%e5%b7%ae%e5%bc%82%e4%b8%bb%e8%a6%81%e5%9c%a8%e6%95%b0%e6%8d%ae%e6%9e%84%e9%80%a0" class="header-anchor"&gt;&lt;/a&gt;六、第五步：进入 SFT 后，差异主要在数据构造&#10;&lt;/h2&gt;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;Pretrain 和 SFT 可以共享同样的 Trainer、DeepSpeed 和大部分训练框架，但它们的数据构造逻辑并不一样。&lt;/strong&gt;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;原因是训练目标不同：Pretrain 学整个文本分布，SFT 学“给定指令后 assistant 应该怎样回答”。&lt;/p&gt;&#10;&lt;p&gt;所以进入 SFT 之后，要先问：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;对话怎么拼&lt;/li&gt;&#10;&lt;li&gt;角色怎么标&lt;/li&gt;&#10;&lt;li&gt;哪些 token 参与 loss&lt;/li&gt;&#10;&lt;li&gt;padding 和 mask 怎么处理&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;第六章这里沿用了 Qwen 风格的 chat template，骨架大致像这样：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;span class="lnt"&gt;12&#10;&lt;/span&gt;&lt;span class="lnt"&gt;13&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;im_start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;|im_start|&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;im_end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;lt;|im_end|&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;IGNORE_TOKEN_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pad_token_id&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;nl_tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;preprocess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_len&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;attention_mask&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pad_token_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="61-这一节要盯住-labels-的构造方式"&gt;&lt;a href="#61-%e8%bf%99%e4%b8%80%e8%8a%82%e8%a6%81%e7%9b%af%e4%bd%8f-labels-%e7%9a%84%e6%9e%84%e9%80%a0%e6%96%b9%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;6.1 这一节要盯住 &lt;code&gt;labels&lt;/code&gt; 的构造方式&#10;&lt;/h3&gt;&lt;p&gt;对 SFT 来说，不是所有 token 都应该参与 loss。&lt;br&gt;&#10;设计上要分清：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;system&lt;/code&gt; 部分不参与拟合&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;user&lt;/code&gt; 部分不参与拟合&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;assistant&lt;/code&gt; 回复部分才是主要监督目标&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这也是为什么 SFT 数据集看起来和 Pretrain 都是 &lt;code&gt;input_ids + labels + attention_mask&lt;/code&gt;，但实际语义完全不同。&lt;/p&gt;&#10;&lt;p&gt;如果用一句更压缩的话来说：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;Pretrain 的 &lt;code&gt;labels&lt;/code&gt; 是整段文本的镜像，SFT 的 &lt;code&gt;labels&lt;/code&gt; 只对回答区域打开监督信号。&lt;/strong&gt;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;h3 id="62-chat-template-是训练协议的一部分"&gt;&lt;a href="#62-chat-template-%e6%98%af%e8%ae%ad%e7%bb%83%e5%8d%8f%e8%ae%ae%e7%9a%84%e4%b8%80%e9%83%a8%e5%88%86" class="header-anchor"&gt;&lt;/a&gt;6.2 &lt;code&gt;chat template&lt;/code&gt; 是训练协议的一部分&#10;&lt;/h3&gt;&lt;p&gt;在 SFT 中，&lt;code&gt;&amp;lt;|im_start|&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;|im_end|&amp;gt;&lt;/code&gt;、角色标识、换行符这些 token 不是普通格式装饰，而是在定义：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;对话轮次边界&lt;/li&gt;&#10;&lt;li&gt;角色身份&lt;/li&gt;&#10;&lt;li&gt;system/user/assistant 的结构关系&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;所以，SFT 数据处理其实是在定义&lt;strong&gt;对话训练协议&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;h3 id="63-attention_mask-和-padding-依然不能忽视"&gt;&lt;a href="#63-attention_mask-%e5%92%8c-padding-%e4%be%9d%e7%84%b6%e4%b8%8d%e8%83%bd%e5%bf%bd%e8%a7%86" class="header-anchor"&gt;&lt;/a&gt;6.3 &lt;code&gt;attention_mask&lt;/code&gt; 和 padding 依然不能忽视&#10;&lt;/h3&gt;&lt;p&gt;到这里之后，padding 会影响：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;哪些位置被模型看到&lt;/li&gt;&#10;&lt;li&gt;哪些位置不参与 loss&lt;/li&gt;&#10;&lt;li&gt;batch 内不同长度样本如何对齐&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;很多实现里 &lt;code&gt;IGNORE_TOKEN_ID&lt;/code&gt; 会取 &lt;code&gt;-100&lt;/code&gt;，因为这是 PyTorch 交叉熵里常见的忽略标签值。第六章的脚本更偏教学示意，复习时重点记“标签遮蔽”这个动作。&lt;/p&gt;&#10;&lt;p&gt;复习锚点：SFT 和 Pretrain 最大的不同，不在 Trainer，而在“谁参与监督”。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="七第六步资源不够时就把全量微调切到-lora"&gt;&lt;a href="#%e4%b8%83%e7%ac%ac%e5%85%ad%e6%ad%a5%e8%b5%84%e6%ba%90%e4%b8%8d%e5%a4%9f%e6%97%b6%e5%b0%b1%e6%8a%8a%e5%85%a8%e9%87%8f%e5%be%ae%e8%b0%83%e5%88%87%e5%88%b0-lora" class="header-anchor"&gt;&lt;/a&gt;七、第六步：资源不够时，就把全量微调切到 LoRA&#10;&lt;/h2&gt;&lt;p&gt;第六章最后补上高效微调。它先介绍 Adapter、Prefix Tuning 等思路，再把重心落到 LoRA：用较少可训练参数完成任务适配。&lt;/p&gt;&#10;&lt;p&gt;LoRA 的形式可以写成：&lt;/p&gt;&#10;$$&#10;W = W_0 + BA&#10;$$&lt;p&gt;其中 $W_0$ 是冻结的原始权重，$A$ 和 $B$ 是低秩增量矩阵。训练时原始权重保持冻结，主要更新这两个低秩矩阵。&lt;/p&gt;&#10;&lt;p&gt;工程落点主要是 &lt;code&gt;peft&lt;/code&gt; 的用法：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 2&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 3&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 4&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 5&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 6&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 7&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 8&#10;&lt;/span&gt;&lt;span class="lnt"&gt; 9&#10;&lt;/span&gt;&lt;span class="lnt"&gt;10&#10;&lt;/span&gt;&lt;span class="lnt"&gt;11&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;peft&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_peft_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LoraConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TaskType&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;peft_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LoraConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;task_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;TaskType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CAUSAL_LM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;inference_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;lora_alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;lora_dropout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_peft_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;peft_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;h3 id="71-lora-在这一章里负责的是把可训练参数缩到更小"&gt;&lt;a href="#71-lora-%e5%9c%a8%e8%bf%99%e4%b8%80%e7%ab%a0%e9%87%8c%e8%b4%9f%e8%b4%a3%e7%9a%84%e6%98%af%e6%8a%8a%e5%8f%af%e8%ae%ad%e7%bb%83%e5%8f%82%e6%95%b0%e7%bc%a9%e5%88%b0%e6%9b%b4%e5%b0%8f" class="header-anchor"&gt;&lt;/a&gt;7.1 LoRA 在这一章里负责的是“把可训练参数缩到更小”&#10;&lt;/h3&gt;&lt;p&gt;它最适合的场景，是：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;模型参数很大&lt;/li&gt;&#10;&lt;li&gt;训练资源有限&lt;/li&gt;&#10;&lt;li&gt;任务更偏行为适配或领域适配&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;在训练链路上，LoRA 给 SFT 这类后训练阶段提供了更轻量的参数更新方式。&lt;/p&gt;&#10;&lt;h3 id="72-peft-抽象了-lora-注入过程"&gt;&lt;a href="#72-peft-%e6%8a%bd%e8%b1%a1%e4%ba%86-lora-%e6%b3%a8%e5%85%a5%e8%bf%87%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;7.2 &lt;code&gt;peft&lt;/code&gt; 抽象了 LoRA 注入过程&#10;&lt;/h3&gt;&lt;p&gt;对工程实践来说，我会记这几件事：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;目标层往往是 &lt;code&gt;q_proj&lt;/code&gt;、&lt;code&gt;v_proj&lt;/code&gt; 这类注意力投影层&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;LoraConfig&lt;/code&gt; 用来描述 LoRA 超参&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;get_peft_model&lt;/code&gt; 会把 LoRA 注入到原模型里&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;实战里要决定：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;微调目标是什么&lt;/li&gt;&#10;&lt;li&gt;LoRA 应该插到哪些层&lt;/li&gt;&#10;&lt;li&gt;rank、dropout、alpha 怎么取&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;div align="center"&gt;&#10; &lt;img src="https://raw.githubusercontent.com/datawhalechina/happy-llm/main/docs/images/6-images/3-2.jpg" alt="LoRA 原理图" width="90%" /&gt;&#10; &lt;p&gt;图：LoRA 用低秩增量更新替代全量参数更新&lt;/p&gt;&#10;&lt;/div&gt;&#10;&lt;h3 id="73-lora-的边界"&gt;&lt;a href="#73-lora-%e7%9a%84%e8%be%b9%e7%95%8c" class="header-anchor"&gt;&lt;/a&gt;7.3 LoRA 的边界&#10;&lt;/h3&gt;&lt;p&gt;LoRA 适合任务适配和低成本后训练；如果目标是让模型吸收大量新知识，它往往不是最理想路径。&lt;/p&gt;&#10;&lt;p&gt;所以从训练链路上看，我更愿意这样理解：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Pretrain 更偏知识底座&lt;/li&gt;&#10;&lt;li&gt;SFT 更偏助手行为塑形&lt;/li&gt;&#10;&lt;li&gt;LoRA 更偏低成本适配&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;复习锚点：LoRA 是把后训练成本压下来的高效微调路线，不是替代预训练的知识注入方案。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="八写在最后第六章搭起的训练骨架"&gt;&lt;a href="#%e5%85%ab%e5%86%99%e5%9c%a8%e6%9c%80%e5%90%8e%e7%ac%ac%e5%85%ad%e7%ab%a0%e6%90%ad%e8%b5%b7%e7%9a%84%e8%ae%ad%e7%bb%83%e9%aa%a8%e6%9e%b6" class="header-anchor"&gt;&lt;/a&gt;八、写在最后：第六章搭起的训练骨架&#10;&lt;/h2&gt;&lt;p&gt;整章可以总结成下面这条主线：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;用 &lt;code&gt;AutoConfig / AutoModel / AutoTokenizer&lt;/code&gt; 接入模型和 tokenizer&lt;/li&gt;&#10;&lt;li&gt;用 &lt;code&gt;datasets.map&lt;/code&gt; 和 &lt;code&gt;group_texts&lt;/code&gt; 把预训练数据整理成 CLM block&lt;/li&gt;&#10;&lt;li&gt;用 &lt;code&gt;TrainingArguments + Trainer&lt;/code&gt; 承接训练骨架&lt;/li&gt;&#10;&lt;li&gt;用 &lt;code&gt;DeepSpeed + ZeRO-2&lt;/code&gt; 把训练推向更真实的多卡脚本环境&lt;/li&gt;&#10;&lt;li&gt;在 SFT 阶段把重心切到 &lt;code&gt;chat template + labels + attention_mask&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;在资源受限时用 &lt;code&gt;LoRA + peft&lt;/code&gt; 替代全量微调&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;第六章搭起来的是一套基于主流框架的训练流程骨架：&lt;/p&gt;&#10;&#10; &lt;blockquote&gt;&#10; &lt;p&gt;&lt;strong&gt;Pretrain -&amp;gt; SFT -&amp;gt; LoRA&lt;/strong&gt;&lt;/p&gt;&#10;&#10; &lt;/blockquote&gt;&#10;&lt;p&gt;这条链路里，每一层的职责也更清楚了：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;模型层负责承接结构和权重&lt;/li&gt;&#10;&lt;li&gt;数据层负责定义训练协议&lt;/li&gt;&#10;&lt;li&gt;Trainer/DeepSpeed 负责承接训练基础设施&lt;/li&gt;&#10;&lt;li&gt;LoRA 负责在后训练阶段压缩更新成本&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;code&gt;6.4&lt;/code&gt; 的偏好对齐部分可以看成全景补充：训练链路后面还会走向奖励模型、RLHF、DPO 等阶段。但第六章落到可复用实践上的重点，仍是前面这条框架化训练主线。&lt;/p&gt;&#10;&lt;p&gt;复习结论：&lt;strong&gt;第六章把大模型训练放进了主流工程栈里，而不是只停在模型结构图上。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="参考资料"&gt;&lt;a href="#%e5%8f%82%e8%80%83%e8%b5%84%e6%96%99" class="header-anchor"&gt;&lt;/a&gt;参考资料&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/datawhalechina/happy-llm/blob/main/docs/chapter6/%E7%AC%AC%E5%85%AD%E7%AB%A0%20%E5%A4%A7%E6%A8%A1%E5%9E%8B%E8%AE%AD%E7%BB%83%E6%B5%81%E7%A8%8B%E5%AE%9E%E8%B7%B5.md" target="_blank" rel="noopener"&#10; &gt;Datawhale. Happy-LLM：第六章《大模型训练流程实践》&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/datawhalechina/happy-llm" target="_blank" rel="noopener"&#10; &gt;Datawhale Happy-LLM 仓库&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/huggingface/transformers" target="_blank" rel="noopener"&#10; &gt;Hugging Face Transformers&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://github.com/huggingface/peft" target="_blank" rel="noopener"&#10; &gt;Hugging Face PEFT&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item></channel></rss>