下面给出 **原教程**(纯 PyTorch / Hugging Face Trainer 方式)与 **Lightning 版**(使用 PyTorch Lightning)在代码结构上的**关键差异**,也就是哪些地方被“简化”或“改动”了。简单来说,Lightning 主要帮我们**“收拢”了训练循环**(forward / backward / 优化器更新 / 日志记录 等),所以凡是原教程里手写或借助其它手段做的地方,都在 Lightning 里被**集中**和**自动**处理了。 --- ## 1. 训练循环的替换 **原教程**: - 人工写 `for epoch in range(epochs):` 循环; - 在循环里做 `model.train()`、`optimizer.zero_grad()`、`loss.backward()`、`optimizer.step()`; - 有时还手动记录 loss、accuracy 等指标,用 `print` 或者手写 logger; - 如果需要验证集/测试集,还要自己写 `with torch.no_grad():` 遍历验证集,然后计算指标。 **Lightning 版**: - 使用 `Trainer.fit(...)`,不再手写 epoch / step 循环; - 将前向逻辑放在 `training_step`,Lightning 会自动调用; - Lightning 会自动帮你做 `.zero_grad()`、`.backward()`、`.step()`; - 通过 `self.log("某指标", 值)` 来记录训练或验证过程中的指标,Lightning 会自动输出并写日志文件; - 在 `validation_step` 里实现验证逻辑,Lightning 同样会自动调用。 因此,原教程里**“显式写循环 + 优化过程”**的代码,在 Lightning 里**全部被省略**: ```python # (原生 PyTorch 示例) for epoch in range(epochs): model.train() for batch in train_dataloader: optimizer.zero_grad() outputs = model(**batch) loss = outputs.loss loss.backward() optimizer.step() # validate... ``` 在 Lightning 版就只剩下: ```python def training_step(self, batch, batch_idx): outputs = self.model(**batch) loss = outputs.loss self.log("train_loss", loss) return loss ... trainer.fit(model, train_dataloaders, val_dataloaders) ``` 再也没有“手动写循环”与“手动 zero_grad / step”,一切都被 Lightning `Trainer` 管理了。 --- ## 2. 优化器、学习率调度等配置的简化 **原教程**: - 需要手动创建 `optimizer = torch.optim.AdamW(model.parameters(), lr=...)`; - 如果用学习率调度器,还要自己写 `scheduler = get_linear_schedule_with_warmup(...)`,并在每个 epoch/step 后 `scheduler.step()`; - 可能还要在训练日志中记录学习率变化。 **Lightning 版**: - 在 `configure_optimizers` 函数中**一次性**返回优化器和调度器,Lightning 内部会自动在合适的时机调用它们: ```python def configure_optimizers(self): optimizer = torch.optim.AdamW(self.parameters(), lr=self.lr) scheduler = get_linear_schedule_with_warmup(...) return [optimizer], [scheduler] ``` - 不再写手动 `scheduler.step()` 之类的逻辑。 --- ## 3. 自动日志记录/打印 **原教程**: - 常见写法:`print(f"epoch={epoch}, loss={loss.item()}")`; - 或者自己集成 TensorBoard / WandB,需要手写 `writer.add_scalar(...)` / `wandb.log(...)`。 **Lightning 版**: - 用 `self.log("metric_name", metric_value, prog_bar=True)`,Lightning 就会把该指标打印到控制台进度条,并可以自动写入日志文件 / TensorBoard / WandB(如果在 `Trainer` 里配好)。 - 无需自己写 `print` 或者手动对接 logger。 --- ## 4. Hugging Face Trainer 被替换 在原教程里,对一些任务(如BERT文本分类、GPT文本生成)我们直接用过 `transformers` 中的 `Trainer` + `TrainingArguments`: ```python trainer = Trainer(model=model, args=training_args, ...) trainer.train() ``` 在 Lightning 版中,我们**不再使用** `Hugging Face` 的 `Trainer`,而是**将模型封装成 LightningModule** 并调用 `pytorch_lightning.Trainer`: ```python class BertForClassificationLightning(pl.LightningModule): ... trainer = pl.Trainer(...) trainer.fit(lightning_module, train_loader, val_loader) ``` 两者本质功能类似(都是封装训练循环),只不过**Lightning 也可更灵活地自定义**,并且统一了你自己写的模块/模型与训练过程。 --- ## 5. 演示脚本 & 测试部分的简化 **原教程**常见的示例: 1. 做一个 `demo_x = torch.zeros(...)`, 2. 调用 `model(demo_x)`, 3. 然后再手写 `loss =...`、`loss.backward()` 以测试网络是否能跑通。 **Lightning 版**里: - 我们往往只写一个小的 `training_step`,然后用 `trainer.fit(model,[demo_x])` 做 1 个 epoch,让它自行前向+反向,看是否报错; - 不需要写多余的脚本去验证**是否能 backward**,因为 Lightning 会自动执行并抛出错误或完成训练。 - 类似地,若要做推断/测试,可直接写 `test_step` + `trainer.test(...)` 或者自己写一个函数 `model(x)` 并推断就行。 所以可以看到,**很多零散的测试脚本**被**Lightning**的训练/验证/测试三个阶段给统一收编了。 --- ## 6. 知识蒸馏 & RL 环节中训练逻辑的精简 **原教程**里知识蒸馏时: - 人工写 loop:先拿 teacher logits → softmax → student logits → KL 散度 → 反向更新。 - 还要自己管理 batch、device 等。 **Lightning 版**: - 上述逻辑直接放进 `training_step` 一次搞定; - 传入的 `batch` 由 DataLoader + Trainer 提供,自动在 GPU 上。 - 不用额外写循环+device分发+日志,只保留**核心公式**即可。 同理,如果要实现**RLHF**或**PPO**,也可以在 `training_step` 里写相应的采样 / 计算策略梯度 / 更新;Lightning 负责 epoch / batch / 分布式 / 日志等通用流程。 --- ## 7. 设备管理 / 分布式 / 深度加速配置 **原教程**: - 如果想要用多 GPU、或分布式,需要自己写 `DistributedDataParallel`、`DataParallel`、或者 DeepSpeed、Horovod 等; - 手动管理 `device = torch.device("cuda" if torch.cuda.is_available() else "cpu")` 并把模型、数据 `.to(device)`; - 可能还要写各种繁琐的分布式初始化代码。 **Lightning 版**: - 只要在 `Trainer(accelerator="gpu", devices=...)` 等指定,就自动管理并行、device 放置、梯度聚合、通信; - 如果想用 DeepSpeed / FSDP / etc.,只要在 `Trainer(strategy="deepspeed_stage_2")` 等启用即可; - 无需自己写 “`model.to(device)`”,Lightning 会自动将模型和数据搬到对应设备。 --- ## 小结 **被“简化”或“改动”的主要就是:** 1. **去掉了所有手写的训练循环**(包括 epoch、mini-batch、optimizer.step 等),改为 `Trainer.fit()` + `training_step`。 2. **去掉了手动日志打印和手动管理 TensorBoard**,改用 `self.log(...)` 由 Lightning 内部管理。 3. **去掉了手动管理 GPU / 分布式**,改用 `Trainer(accelerator=..., devices=..., strategy=...)`。 4. **去掉了 Hugging Face 的 `Trainer`**(如果原教程里使用它),改成 LightningModule + Lightning 的 `Trainer`。 5. **demo/测试脚本**(比如验证网络能否 forward+backward)也用 Lightning 的 fit 或 test 来做演示,而不手写 `for step in range(steps)`。 除了上述变化,**模型的原理、网络结构、注意力/FFN 等组件**都**与原教程一致**。你只需把它们写进 LightningModule,剩下的训练与验证流程就不用再手写了。这样代码更统一、更短、也更易扩展到分布式大模型场景。 --- 希望这能帮助你快速了解:**Lightning 版 与 原教程版** 的主要“简化”之处究竟在哪里。祝学习顺利! 下面是一份**基于原教程结构**、使用 **PyTorch Lightning** 来组织训练流程的示例版本。为方便理解,本文在保留原教程的主要内容与思路的同时,会重点演示如何在关键步骤中使用 PyTorch Lightning 的 **LightningModule**、**Trainer** 等接口,让训练、验证以及部署流程更加简洁与标准化。由于教程内容非常丰富,以下示例代码不会一字不漏地替换每行原生 PyTorch 代码,但会展示最核心的 Lightning 使用方式。读者可结合此思路,将原教程中的其他部分迁移为 Lightning 风格。 --- ## 六周 Transformer 模型实践教程(PyTorch Lightning 版) |周数 (Week)|目标 (Goal)| |---|---| |第一周|搭建环境,了解 Transformer 架构和自注意力机制,完成第一个文本生成示例。| |第二周|理解 Transformer 核心组件:词嵌入、位置编码、多头注意力、前馈网络等。| |第三周|组装简化版 Transformer 块,并通过微调预训练模型完成文本分类。| |第四周|高级应用:文本生成、模型压缩、提示工程与评估指标。| |第五周|更高级技巧:高效训练策略、模型伦理与公平、多模态模型、优化部署等。| |第六周|了解最新研究:稀疏化(MoE)、强化学习对齐(RLHF)、自主 AI Agent 原理等。| --- ### ❤️ 第一周:基本概念 (Lightning 版) #### 步骤1:环境搭建(Python/PyTorch/Hugging Face Transformers + PyTorch Lightning) 与原教程相同,先在 Google Colab 或本地环境中安装必要包: ```bash !pip install torch torchvision transformers pytorch-lightning --upgrade ``` 然后验证环境,示例代码可直接使用原教程中的方式(比如打印版本信息和 `torch.cuda.is_available()`)。 #### 步骤2:使用 Lightning 体验预训练模型的前向传播 下面我们先演示**不**使用 LightningModule,而只是结合 Lightning 的 Trainer 来做一个简单推理,帮助大家熟悉 Lightning 的基本调用方式。在真正写 LightningModule 之前,我们可以像原生 PyTorch 一样加载模型,只是把 “推理” 或 “验证” 的过程托管给 Lightning 的 Trainer。 ```python import torch import pytorch_lightning as pl from transformers import AutoTokenizer, AutoModel # 加载DistilBERT分词器与模型 tokenizer = AutoTokenizer.from_pretrained('distilbert-base-uncased') model = AutoModel.from_pretrained('distilbert-base-uncased') text = "Hello world" inputs = tokenizer(text, return_tensors="pt") # 由于这里只是做一次前向推理,不定义训练过程,所以可以使用Lightning的LightningModule空壳 class InferenceModule(pl.LightningModule): def __init__(self, model): super().__init__() self.model = model def forward(self, **inputs): return self.model(**inputs) inference_module = InferenceModule(model) # 我们用 Trainer 来做一个测试步骤 trainer = pl.Trainer( max_epochs=1, logger=False, enable_checkpointing=False, enable_model_summary=False ) # 直接手动调用 forward 看输出 outputs = inference_module(**inputs) print("输出张量维度:", outputs.last_hidden_state.shape) ``` 这里因为没有真实的训练或验证集,所以我们用 `Trainer` 没有什么实际意义,但你可以通过这样的方式,日后把训练/验证/测试等过程放到 Lightning 中统一管理。 --- #### 步骤3:自注意力机制(Scaled Dot-Product Attention) 原教程中写了一个简化注意力的函数 `scaled_dot_product_attention(Q, K, V)`. 在 Lightning 中,这段逻辑通常写在 LightningModule 内部或者封装成一个独立的 nn.Module。下面给出一个**独立模块**示例,保留原公式,方便后续被 LightningModule 调用。 ```python import torch import torch.nn.functional as F class ScaledDotProductAttention(torch.nn.Module): def __init__(self): super().__init__() def forward(self, Q, K, V): d_k = Q.size(-1) scores = torch.matmul(Q, K.transpose(-2, -1)) / (d_k ** 0.5) weights = F.softmax(scores, dim=-1) output = torch.matmul(weights, V) return output, weights ``` 后续在真正的 LightningModule 中,可以直接实例化并调用 `ScaledDotProductAttention` 来做自注意力计算。 --- #### 步骤4:基础文本生成(Lightning 版) 让我们快速演示一下**文本生成**的 Lightning 用法——实际上,Hugging Face 提供的 `generate()` 方法并不需要 Lightning 的训练循环。但如果你想要在 Lightning 的范式下做**训练+生成**,则可以把生成逻辑写在 `validation_step` 或 `test_step` 里。下面演示一个最基本的**LightningModule + Trainer**做文本生成推理: ```python from transformers import AutoModelForCausalLM, AutoTokenizer import pytorch_lightning as pl class GPT2InferenceModule(pl.LightningModule): def __init__(self, model_name="distilgpt2"): super().__init__() self.save_hyperparameters() self.tokenizer = AutoTokenizer.from_pretrained(model_name) self.model = AutoModelForCausalLM.from_pretrained(model_name) def forward(self, input_ids, max_length=30): # 仅做生成 generated_ids = self.model.generate( input_ids=input_ids, max_length=max_length ) return generated_ids # 初始化 gpt2_module = GPT2InferenceModule("distilgpt2") trainer = pl.Trainer(logger=False, enable_checkpointing=False) # 推断 prompt = "Hello, my name is" input_ids = gpt2_module.tokenizer(prompt, return_tensors='pt').input_ids generated_ids = gpt2_module(input_ids) output_text = gpt2_module.tokenizer.decode(generated_ids[0], skip_special_tokens=True) print("生成文本:", output_text) ``` 这样虽然有点“多此一举”,但展示了可以用 LightningModule 包装预训练模型,便于后续扩展训练环节。 --- ### ❤️ 第二周:核心组件 (Lightning 版) 下面展示如何把**词嵌入、位置编码、多头注意力、前馈网络**等核心组件封装进一个 LightningModule 或者普通的 PyTorch Module。然后 LightningModule 在 `training_step` 中调用这些模块进行前向传播,并依赖 Trainer 的循环机制来完成训练。 #### 步骤5:Word Embedding(词嵌入)+ Lightning 用法 Lightning 对“组件”层面没有特别要求,与普通 PyTorch nn.Module 相同。只要在 `LightningModule` 的 `forward` 内部正确调用即可。示例: ```python import torch import torch.nn as nn import pytorch_lightning as pl class EmbeddingDemo(pl.LightningModule): def __init__(self, vocab_size=10, embed_dim=4): super().__init__() self.embedding = nn.Embedding(num_embeddings=vocab_size, embedding_dim=embed_dim) # 为了让Lightning能训练,需要一个优化器,哪怕只是演示 self.lr = 1e-3 def forward(self, x): return self.embedding(x) def configure_optimizers(self): return torch.optim.Adam(self.parameters(), lr=self.lr) def training_step(self, batch, batch_idx): # 假设 batch 就是单词索引 embedded = self.forward(batch) loss = embedded.mean() # 随便定义一个loss演示 self.log("train_loss", loss) return loss # 演示:训练一个 epoch demo_model = EmbeddingDemo() trainer = pl.Trainer(max_epochs=1, logger=False, enable_checkpointing=False) fake_data = torch.randint(0, 10, (16,)) # 假设batch=16 trainer.fit(demo_model, train_dataloaders=[fake_data]) ``` 这里 `fake_data` 只是一个纯数字张量充当索引,实际中你会用 DataLoader 产出真正的 token id。Lightning 会自动帮你做前向、反向和优化步骤。 --- #### 步骤6:Positional Encoding(位置编码) 可以依旧定义一个独立的 `PositionalEncoding` 模块,然后在 LightningModule 中初始化和调用: ```python import math class PositionalEncoding(nn.Module): def __init__(self, d_model, max_len=5000): super().__init__() pe = torch.zeros(max_len, d_model) position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] = torch.sin(position * div_term) pe[:, 1::2] = torch.cos(position * div_term) pe = pe.unsqueeze(0) # shape [1, max_len, d_model] self.register_buffer('pe', pe) def forward(self, x): # x shape: [batch_size, seq_len, d_model] seq_len = x.size(1) x = x + self.pe[:, :seq_len, :] return x ``` 使用时只需在 LightningModule 的 `forward` 中调用: ```python class TransformerEmbeddingsLightning(pl.LightningModule): def __init__(self, vocab_size=100, d_model=32, max_len=128): super().__init__() self.embedding = nn.Embedding(vocab_size, d_model) self.pos_encoding = PositionalEncoding(d_model, max_len) self.lr = 1e-3 def forward(self, x): embed = self.embedding(x) out = self.pos_encoding(embed) return out def configure_optimizers(self): return torch.optim.Adam(self.parameters(), lr=self.lr) def training_step(self, batch, batch_idx): out = self(batch) # 伪造一个loss loss = out.mean() self.log("train_loss", loss) return loss ``` --- #### 步骤7:Multi-Head Attention(多头注意力)+ Lightning 在 Lightning 中使用多头注意力,与普通 PyTorch 几乎相同,只是在训练循环中更简洁。我们可以直接用 `nn.MultiheadAttention` 或自己实现都行。下面演示**自定义**一个 LightningModule,包含多头注意力进行前向。训练数据依然是伪造的。 ```python class MultiHeadAttentionDemo(pl.LightningModule): def __init__(self, embed_dim=8, num_heads=2): super().__init__() self.mha = nn.MultiheadAttention(embed_dim, num_heads, batch_first=True) self.lr = 1e-3 def forward(self, x): # x shape: [batch, seq_len, embed_dim] attn_out, attn_weights = self.mha(x, x, x) return attn_out, attn_weights def configure_optimizers(self): return torch.optim.Adam(self.parameters(), lr=self.lr) def training_step(self, batch, batch_idx): x = batch out, w = self(x) loss = out.mean() self.log("loss", loss) return loss # 伪造一个 x: batch=2, seq_len=5, embed_dim=8 dummy_x = torch.randn(2, 5, 8) demo_mha = MultiHeadAttentionDemo() trainer = pl.Trainer(max_epochs=1, logger=False, enable_checkpointing=False) trainer.fit(demo_mha, train_dataloaders=[dummy_x]) ``` --- #### 步骤8:Feed-Forward 模块(前馈网络)+ Lightning 同理,前馈网络可以是一个普通 `nn.Sequential`,在 LightningModule 中做前向和训练: ```python class FFNLightning(pl.LightningModule): def __init__(self, embed_dim=8, hidden_dim=16): super().__init__() self.ffn = nn.Sequential( nn.Linear(embed_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, embed_dim) ) self.lr = 1e-3 def forward(self, x): return self.ffn(x) def configure_optimizers(self): return torch.optim.Adam(self.parameters(), lr=self.lr) def training_step(self, batch, batch_idx): out = self(batch) loss = out.mean() self.log("loss", loss) return loss dummy_x = torch.randn(2, 5, 8) ffn_module = FFNLightning() trainer = pl.Trainer(max_epochs=1, logger=False, enable_checkpointing=False) trainer.fit(ffn_module, train_dataloaders=[dummy_x]) ``` --- ### ❤️ 第三周:实践入门 (Lightning 版) #### 步骤9:实现简化版 TransformerBlock 结合前面组件:多头自注意力 + 前馈网络 + LayerNorm + 残差,做成一个 **nn.Module**,再被 LightningModule 调用。 ```python class TransformerBlock(nn.Module): def __init__(self, d_model, nhead, dim_ff): super().__init__() self.self_attn = nn.MultiheadAttention(embed_dim=d_model, num_heads=nhead, batch_first=True) self.ffn = nn.Sequential( nn.Linear(d_model, dim_ff), nn.ReLU(), nn.Linear(dim_ff, d_model) ) self.norm1 = nn.LayerNorm(d_model) self.norm2 = nn.LayerNorm(d_model) def forward(self, x): attn_out, _ = self.self_attn(x, x, x) x = self.norm1(x + attn_out) ffn_out = self.ffn(x) x = self.norm2(x + ffn_out) return x # 将其封装到 LightningModule 中,以便训练 class SimpleTransformerLightning(pl.LightningModule): def __init__(self, d_model=4, nhead=1, dim_ff=4): super().__init__() self.block = TransformerBlock(d_model, nhead, dim_ff) self.lr = 1e-3 def forward(self, x): return self.block(x) def configure_optimizers(self): return torch.optim.Adam(self.parameters(), lr=self.lr) def training_step(self, batch, batch_idx): out = self(batch) loss = out.mean() self.log("loss", loss) return loss # 测试 demo = SimpleTransformerLightning() dummy_x = torch.zeros(2,3,4) trainer = pl.Trainer(max_epochs=1, logger=False, enable_checkpointing=False) trainer.fit(demo, train_dataloaders=[dummy_x]) ``` 此时就能复现原教程中对 TransformerBlock 的测试方式,只不过我们把训练循环用 Lightning 接管了。 --- #### 步骤10 & 11:微调预训练模型(BERT)+ 文本分类 (Lightning 版) 重点来了:使用 Lightning 来微调 BERT。我们可以通过 `transformers` 提供的 `AutoModelForSequenceClassification` 进行初始化,然后在 LightningModule 中实现 `forward`、`training_step`、`validation_step` 等。 1. **准备数据**:与原教程一样使用 `datasets` 加载 IMDB,tokenize 后得到 DataLoader。 2. **LightningModule**:包装预训练模型 + 优化器 + 训练/验证逻辑。 示例如下: ```python !pip install datasets evaluate import torch import torch.nn as nn import torch.nn.functional as F import pytorch_lightning as pl from datasets import load_dataset from transformers import AutoTokenizer, AutoModelForSequenceClassification # 加载IMDB子集 dataset_train = load_dataset("imdb", split="train[:2000]") dataset_val = load_dataset("imdb", split="test[:500]") model_name = "bert-base-uncased" tokenizer = AutoTokenizer.from_pretrained(model_name) def tokenize_batch(batch): return tokenizer(batch["text"], padding=True, truncation=True, max_length=128) dataset_train = dataset_train.map(tokenize_batch, batched=True) dataset_val = dataset_val.map(tokenize_batch, batched=True) dataset_train = dataset_train.remove_columns(["text"]) dataset_val = dataset_val.remove_columns(["text"]) dataset_train.set_format("torch") dataset_val.set_format("torch") # 建立 DataLoader def collate_fn(batch): return { "input_ids": torch.stack([x["input_ids"] for x in batch]), "attention_mask": torch.stack([x["attention_mask"] for x in batch]), "labels": torch.tensor([x["label"] for x in batch]) } train_loader = torch.utils.data.DataLoader(dataset_train, batch_size=16, shuffle=True, collate_fn=collate_fn) val_loader = torch.utils.data.DataLoader(dataset_val, batch_size=16, shuffle=False, collate_fn=collate_fn) # LightningModule 封装微调逻辑 class BertForClassificationLightning(pl.LightningModule): def __init__(self, model_name="bert-base-uncased", num_labels=2, lr=2e-5): super().__init__() self.save_hyperparameters() self.model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=num_labels) def forward(self, input_ids, attention_mask, labels=None): return self.model(input_ids=input_ids, attention_mask=attention_mask, labels=labels) def training_step(self, batch, batch_idx): outputs = self( input_ids=batch["input_ids"], attention_mask=batch["attention_mask"], labels=batch["labels"] ) loss = outputs.loss self.log("train_loss", loss, prog_bar=True) return loss def validation_step(self, batch, batch_idx): outputs = self( input_ids=batch["input_ids"], attention_mask=batch["attention_mask"], labels=batch["labels"] ) val_loss = outputs.loss preds = torch.argmax(outputs.logits, dim=1) acc = (preds == batch["labels"]).float().mean() self.log("val_loss", val_loss, prog_bar=True) self.log("val_acc", acc, prog_bar=True) return val_loss def configure_optimizers(self): return torch.optim.AdamW(self.parameters(), lr=self.hparams.lr) # 训练 model_light = BertForClassificationLightning(model_name, num_labels=2, lr=2e-5) trainer = pl.Trainer(max_epochs=1, accelerator="gpu" if torch.cuda.is_available() else "cpu") trainer.fit(model_light, train_dataloaders=train_loader, val_dataloaders=val_loader) ``` 这样就完成了**基于 Lightning** 的 BERT 分类微调。Lightning 的好处在于,如果你要加上 `learning_rate_scheduler`、`loggers`、`checkpoint` 等,都可以在 `Trainer` 中灵活配置,而不用手写太多循环代码。 **推理**也很简单,可以在 `validation_epoch_end` 或 `predict` 模式中进行,或者自己写个函数手动调用: ```python def predict_sentiment(model, text: str): model.eval() inputs = tokenizer(text, return_tensors="pt") with torch.no_grad(): outputs = model(input_ids=inputs["input_ids"], attention_mask=inputs["attention_mask"]) logits = outputs.logits pred = torch.argmax(logits, dim=1).item() return "Positive" if pred == 1 else "Negative" print(predict_sentiment(model_light, "This movie is fantastic, I love it!")) ``` --- ### ❤️ 第四周:进阶应用 (Lightning 版) 在这一周,我们学习了**文本生成**、**知识蒸馏**、**提示工程**、**评估指标**等。在 Lightning 里,它们的核心原理并无变化,只是将训练循环迁移到 Lightning 中更简洁。下面挑**知识蒸馏**做个 Lightning 展示。 #### 知识蒸馏(Knowledge Distillation)+ Lightning 思路:**Teacher**(已经训练好的大模型)在推理模式下,给每个样本产生 logits → softmax → 作为 soft label;**Student** 用 KL 散度学习逼近 Teacher 的输出分布。 ```python import torch.nn.functional as F import pytorch_lightning as pl class DistillationLightning(pl.LightningModule): def __init__(self, teacher_model, student_model, lr=3e-4): super().__init__() self.teacher = teacher_model.eval() # 冻结教师 for p in self.teacher.parameters(): p.requires_grad = False self.student = student_model self.lr = lr def forward(self, **inputs): # 学生前向 return self.student(**inputs) def training_step(self, batch, batch_idx): # 1) 教师输出 with torch.no_grad(): teacher_out = self.teacher( input_ids=batch["input_ids"], attention_mask=batch["attention_mask"] ) teacher_probs = F.softmax(teacher_out.logits, dim=-1) # 2) 学生输出 student_out = self.student( input_ids=batch["input_ids"], attention_mask=batch["attention_mask"] ) student_log_probs = F.log_softmax(student_out.logits, dim=-1) # 3) KL 散度 loss = F.kl_div(student_log_probs, teacher_probs, reduction='batchmean') self.log("distill_loss", loss) return loss def configure_optimizers(self): return torch.optim.Adam(self.student.parameters(), lr=self.lr) # 演示:teacher 用之前微调好的 model_light, student 用小模型 DistilBERT from transformers import AutoModelForSequenceClassification student_model = AutoModelForSequenceClassification.from_pretrained("distilbert-base-uncased", num_labels=2) distill_module = DistillationLightning(model_light.model, student_model) trainer = pl.Trainer(max_epochs=1) trainer.fit(distill_module, train_loader) ``` --- ### ❤️ 第五周:高级主题 (Lightning 版) **分布式训练 (DeepSpeed / FSDP / ZeRO)**、**模型伦理**、**多模态(CLIP, DALL·E)**、**部署(ONNX/TensorRT)** 等,都可以按照 Lightning 方式来处理训练或推理循环。比如: - **DeepSpeed + Lightning**: 只要在 `Trainer` 中指定 `strategy="deepspeed_stage_2"` 或者传递配置文件,即可把LightningModule的训练过程托管到 DeepSpeed。示例: ```python trainer = pl.Trainer( max_epochs=3, strategy="deepspeed_stage_2", devices=2, accelerator="gpu" ) trainer.fit(model_light, train_dataloaders=train_loader, val_dataloaders=val_loader) ``` - **多模态**:跟前面类似,把 CLIP 或 Stable Diffusion 的模型写在 `LightningModule` 里,或者直接做推断。 - **ONNX 导出**:LightningModule 也只是 PyTorch 模型,你可以和原生 PyTorch 一样使用 `torch.onnx.export()`,只要把 `self.model` 取出来即可。 --- ### ❤️ 第六周:前沿探索 (Lightning 版) **MoE 架构**、**RLHF**、**Agent** 思路与本质实现也不冲突。LightningModule 可帮助你管理大规模训练、分布式等,但核心原理与原教程一致。比如: - **MoE**:可在 LightningModule 构造函数中初始化多个专家子网络,forward 中写好门控逻辑,训练时定义好 `training_step`。 - **RLHF**:可把 **reward model** / **策略模型** / **算法** 整合在一个 LightningModule 或多个 LightningModule 中,更好地管理超参和日志。 - **Agent**:如果需要循环式地调用大模型、外部工具,可在 `validation_step` 或自定义的推理脚本中完成 agent 的思维过程;Lightning 主要帮助你管理模型的权重和训练流程,agent 的多轮 loop 需要自己写 Python 逻辑或借助 [Lightning Flow](https://lightning.ai/) 之类的生态,但那是更高层的工作流管理。 --- ## 总结 通过以上示例,可以看到: - **LightningModule** 主要解决了**训练循环**(前向、反向、优化器更新、日志记录等)的简化问题,与原教程中的**模型原理**、**注意力计算**、**微调思路**等完全兼容。 - 你可以把原教程中任何基于 `nn.Module` + 手写 `for epoch in range(epochs)` 的代码改写成 LightningModule + Trainer.fit() 的方式,从而获得更简洁的代码、自动断点续训、自动日志、分布式训练等优势。 - 其余原教程提到的**推理、评估、提示工程**等环节,不一定要用 Lightning,但如果你喜欢统一风格,也可以把推理过程写进 `test_step` 或专门函数里。 希望以上**PyTorch Lightning 版本**的示例,能帮助你在保留 Transformer 教程核心知识与实践流程的同时,享受到 Lightning 带来的更干净、更便捷的训练体验。祝你学有所成,玩转 Lightning 下的各种 Transformer 应用!