linear / relu / sgd -> tokenization -> LLM workflow -> inference / deployment

SGD、Linear、ReLU

神经网络为什么能工作

神经网络本质上不是神秘黑盒,而是很多简单函数的组合。

最基础的一条链可以写成:

x -> Linear -> ReLU -> Linear -> loss -> backward -> SGD step

Linear 是什么

nn.Linear 做的是一个仿射变换。
它会把输入特征映射到新的特征空间。

例如:

  • 输入是 in_features
  • 输出是 out_features

对应代码

1
2
3
4
5
6
7
8
9
import torch
from torch import nn

linear = nn.Linear(4, 2)
x = torch.randn(3, 4)
y = linear(x)

print("x shape:", x.shape)
print("y shape:", y.shape)

需要记住的点

  • Linear 层本身有参数
  • 这些参数通常包括 weightbias
  • 训练时被更新的,就是这些参数

为什么只有线性层不够

如果一个模型里只有线性层,那么无论叠多少层,整体仍然只是一个线性变换。
这意味着模型表达能力有限,不能表示复杂函数。

所以,神经网络真正变强的关键,不只是“层数变多”,而是:

在线性层之间加入非线性。

ReLU 是什么

ReLU(x) = max(0, x)

也就是:

  • 正数保留
  • 负数变成 0

为什么需要 ReLU

ReLU 是非线性激活函数。
加入 ReLU 后,模型就不再只是简单线性变换的堆叠,而可以表达更复杂的函数关系。

对应代码

1
2
3
4
5
6
7
8
9
10
import torch
from torch import nn

relu = nn.ReLU()

x = torch.tensor([[-1.0, 0.5, 2.0]])
y = relu(x)

print("before relu:", x)
print("after relu:", y)

SGD 是什么

SGD(Stochastic Gradient Descent)做的事情是:

  1. 用当前 batch 计算 loss
  2. 根据 loss 反向传播得到梯度
  3. 按学习率更新参数

也就是:

1
param = param - lr * grad

为什么叫 stochastic

因为它通常不是每次用整个数据集精确计算梯度,
而是只用当前一个 batch 来近似当前梯度。

学习率为什么重要

学习率过大:

  • 参数更新步子太大
  • 容易在某个范围内震荡
  • 甚至可能直接发散

学习率过小:

  • loss 下降太慢
  • 训练时间过长
  • 可能很久都看不到明显改善

需要记住的点

  • 梯度决定方向
  • 学习率决定步长

Tokenization

tokenization 是什么

语言模型不能直接处理原始文本。
文本在进入模型之前,必须先被转换成模型能处理的离散单位和数字表示。

这个过程就是 tokenization。

最小视角下,tokenizer 做两件事:

  1. 把文本切成 token
  2. 把 token 转成 token id

token 是什么

token 是模型输入的基本单位。
在现代 LLM 中,token 往往既不是完整单词,也不是单个字符,而更常是 subword(子词)

为什么不用纯单词切分

如果按完整单词切分:

  • 词表会非常大
  • 遇到新词、罕见词时处理很差
  • 语言泛化能力不够好

为什么不用纯字符切分

如果按单个字符切分:

  • 序列会变得很长
  • 训练和推理成本会变高
  • 对模型来说不一定是更好的表示方式

所以现代 tokenizer 通常在两者之间取折中,使用 subword。

subword tokenization

需要认识 3 个名字:

  • BPE
  • WordPiece
  • Unigram

它们的共同目标都是:

在控制词表大小的同时,尽可能保留有意义的文本片段。

对 CJK 的处理

对于中文、日文、韩文,tokenizer 通常不会简单按空格切分,
而更可能按字符边界、子词规则,或者直接在原始文本上学习切分方式。

所以:

  • 中文里常常接近按字或短片段切
  • 日文和韩文也常结合 subword 方法处理
  • 同一句 CJK 文本,在不同 tokenizer 下可能切分结果不同

special tokens 是什么

除了普通文本 token,tokenizer 通常还会管理一些特殊 token,例如:

  • BOS
  • EOS
  • CLS
  • SEP
  • PAD

这说明模型输入不只是正文 token,还包含一些控制信息。

token 数为什么重要

token 数会直接影响:

  • 输入序列长度
  • 上下文窗口占用
  • 推理成本
  • 延迟和吞吐
  • 系统性能

所以 tokenizer 不是一个无关紧要的文本前处理步骤,
它实际上是模型系统的一部分。

最小例子

1
2
3
4
5
6
7
8
9
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")

text = "I like machine learning."
encoded = tokenizer(text)

print("input_ids:", encoded["input_ids"])
print("tokens:", tokenizer.convert_ids_to_tokens(encoded["input_ids"]))

LLM 的最小全景图

LLM 是什么

LLM(Large Language Model)是在大量文本数据上训练出来的语言模型。
它可以理解和生成文本,并且在不做任务专门训练的情况下,处理很多语言任务。

这里要注意:

  • 不是所有任务都能直接做好
  • 也不是永远不需要进一步适配
  • 但相比传统 NLP,LLM 的泛化能力更强

training / fine-tuning / inference

training / pretraining:

  • 从大量数据中训练模型
  • 学习通用语言模式
  • 得到一个基础模型

fine-tuning:

  • 在已有预训练模型基础上继续训练
  • 用更具体的数据做适配
  • 让模型更适合某个任务、领域或风格

inference:

  • 使用现有模型做预测或生成
  • 不再更新模型参数
  • 只做前向计算

deployment / serving:

  • 把 inference 包装成一个可调用的服务
  • 对外提供接口或应用
  • 让模型真正可用

为什么“做 LLM”不等于“只看模型结构”

做 LLM 不只是看 transformer 结构或者参数量。

一个真实的 LLM 工作流还包括:

  • data
  • tokenizer
  • model
  • training / fine-tuning
  • inference
  • serving
  • 工具链与模型管理

也就是说:

模型只是系统的一部分,不是全部。

最小流程图

1
data -> tokenizer -> model -> training/fine-tuning -> inference -> serving -> agent

Deployment Awareness

为什么训练脚本不等于部署

训练脚本的职责是:

  • 加载数据
  • 计算 loss
  • 反向传播
  • 更新参数

而部署需要的是:

  • 一个稳定的推理入口
  • 接受输入
  • 返回预测结果
  • 对外提供服务

所以训练代码和部署代码不是一回事。

inference script 最小需要什么

一个最小推理脚本通常需要:

  1. 加载模型结构
  2. 加载模型权重
  3. 切到 model.eval()
  4. 接受输入
  5. 做前向计算
  6. 返回预测结果

如果是文本模型,还通常需要:

  • 加载 tokenizer

为什么 model.eval() 在部署里很重要

推理阶段一般需要稳定、可复现的输出。
如果不切到 eval()

  • Dropout 可能还在随机丢弃神经元
  • BatchNorm 可能还在使用当前 batch 的统计量

这会导致推理结果不稳定。

所以部署时通常会写:

1
2
3
model.eval()
with torch.no_grad():
output = model(x)

最小 Web demo 的核心抽象

最小 Web demo 的核心不是“服务器”,而是:

input -> predict_function -> output

也就是说,本质上你只需要先写一个预测函数,然后再把它包装成界面或接口。

一个最小 Gradio 例子

1
2
3
4
5
6
7
8
9
10
11
12
import gradio as gr

def predict(text):
return f"you entered: {text}"

demo = gr.Interface(
fn=predict,
inputs="text",
outputs="text"
)

demo.launch()

这里最关键的是:

  • fn:预测函数
  • inputs:输入类型
  • outputs:输出类型

最重要的结论

  1. 线性层负责做特征映射。
  2. 只有线性层不够,因为整体仍然是线性函数。
  3. ReLU 这样的非线性激活函数让模型具备更强表达能力。
  4. SGD 用 batch 的梯度近似来更新参数。
  5. tokenizer 负责把文本切成 token,并转换成 token id。
  6. 现代模型常使用 subword,而不是纯单词或纯字符。
  7. token 数会影响上下文长度、推理成本和系统性能。
  8. LLM 是在大规模文本上训练出来的语言模型。
  9. training、fine-tuning、inference、deployment 是不同阶段。
  10. 做 LLM 工程不是只看模型结构,而是整条工作流。
  11. 训练代码负责更新参数,推理代码负责接受输入并输出预测。
  12. 最小 Web demo 的核心抽象是:input -> prediction function -> output

到这里,应该已经能做到

  • 理解 Linear 层在做什么
  • 理解为什么神经网络需要非线性激活函数
  • 理解 ReLU 的作用
  • 理解 SGD 为什么能让 loss 下降
  • 理解学习率对训练速度和稳定性的影响
  • 理解 token、word、character 的区别
  • 理解 tokenizer 的最小职责
  • 知道常见 subword 算法名字
  • 知道 token 数为什么影响 LLM 系统表现
  • 理解 LLM 的基本定义和工作流
  • 区分 training / fine-tuning / inference / deployment
  • 理解训练脚本和推理脚本的区别
  • 理解为什么部署前必须 model.eval()
  • 理解最小 Web demo 的抽象方式

References

从神经网络基础到 LLM 与部署