想入门 NLP但面对 Transformer、BERT、LLM 这些层出不穷的术语是不是感觉无从下手网上教程要么是晦涩的数学公式要么是零散的代码片段学了半天还是不知道如何把它们串起来解决一个实际问题。这篇文章要解决的就是这个痛点。我的核心判断是NLP 入门的关键不在于死磕某个模型的数学细节而在于快速建立“问题-模型-工具”的映射关系并亲手跑通一个从数据到结果的完整流程。很多初学者卡在理论里恰恰是因为缺少一次“从零到一”的实战体验。本文将带你用 2026 年的视角重新梳理 NLP 的核心脉络。我们不追求成为理论专家而是聚焦于当你拿到一段文本数据时如何判断该用 LSTM、Transformer 还是 BERT如何用 PyTorch 快速搭建并训练一个模型以及在 LLM 当道的今天传统的序列模型还有哪些不可替代的价值读完本文你将能清晰地理解 NLP 主流模型RNN/LSTM/Transformer/BERT的适用场景与核心差异并亲手完成一个基于 LSTM 的文本分类实战项目。更重要的是你会建立起一套属于自己的 NLP 问题解决框架知道下一步该往哪里深入。1. 从“黑话”到工具重新理解 NLP 技术栈在深入代码之前我们必须先理清概念。很多初学者感到混乱是因为把不同层次的概念混为一谈。我们可以把 NLP 技术栈分为四个层次第一层任务定义层。这是你要解决的具体问题比如情感分析判断评论正负面、命名实体识别找出文本中的人名、地名、机器翻译、文本摘要等。第二层模型架构层。这是解决任务的“算法蓝图”。过去十年主流架构经历了从RNN/LSTM到Transformer的演变。LSTM 擅长处理有前后依赖关系的序列如时间序列、文本而 Transformer 凭借其“自注意力”机制能更好地捕捉长距离依赖并行效率也更高成为当前大模型的基石。第三层预训练模型层。这是基于特定架构在海量文本上预先训练好的“知识库”。BERT就是基于 Transformer 架构的著名预训练模型。你不需要从零开始训练只需在 BERT 学到的通用语言知识基础上用你的业务数据做微调就能快速得到一个高质量模型。这大大降低了 NLP 的应用门槛。第四层大语言模型层。这是预训练模型的进一步升级通常指参数量巨大如千亿级、能力极强的模型如 GPT、LLaMA 等。它们通常基于 Transformer 的 Decoder 部分具备强大的生成和理解能力。对于大多数入门和中级任务我们更多是“调用”而非“训练”LLM。它们之间的关系可以用一个简单的表格来厘清层次代表技术核心作用与开发者的关系类比任务情感分析、NER定义要解决的问题明确需求“我要造一辆车”架构RNN/LSTM,Transformer提供解决问题的算法框架选择技术路线“我选择内燃机还是电动机作为动力方案”预训练模型BERT, RoBERTa提供预先学好的通用语言知识站在巨人肩膀上微调“我直接采购一台成熟的发动机然后适配我的车架”大语言模型GPT-4, LLaMA提供开箱即用的强大语言能力主要作为API调用或轻量级微调“我直接调用一个成熟的‘自动驾驶系统’服务”对于初学者最容易产生的误解是认为 Transformer 和 BERT 是并列关系或者认为 LSTM 已经彻底过时。实际上Transformer 是一种架构BERT 是基于该架构的一个具体模型实例。而 LSTM 在数据量较小、序列顺序性极强的任务如某些传感器时序预测中依然有其简洁高效的优势。接下来我们将从最经典、最能体现序列建模思想的 LSTM 入手完成一个完整的实战项目。理解它是理解更复杂模型的基础。2. 环境准备构建可复现的 PyTorch 开发环境工欲善其事必先利其器。一个独立、版本清晰的环境是避免“跑不通代码”噩梦的第一步。强烈建议使用 Conda 或 venv 创建虚拟环境。2.1 创建并激活虚拟环境# 使用 conda推荐 conda create -n nlp_tutorial python3.9 conda activate nlp_tutorial # 或者使用 venv python -m venv nlp_tutorial # Windows nlp_tutorial\Scripts\activate # Linux/Mac source nlp_tutorial/bin/activate2.2 安装核心依赖我们将使用 PyTorch 作为深度学习框架并用 torchtext 来处理文本数据。请注意torchtext 的 API 在较新版本中有较大变化为了教程稳定我们指定一个广泛兼容的版本。# 安装 PyTorch (请根据你的CUDA版本前往 https://pytorch.org/ 获取最新命令) # 此处以CPU版本为例适合所有环境 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu # 安装 torchtext 和必要工具 pip install torchtext0.15.2 pip install scikit-learn pandas tqdm验证安装import torch import torchtext print(fPyTorch 版本: {torch.__version__}) print(fTorchtext 版本: {torchtext.__version__}) print(fCUDA 是否可用: {torch.cuda.is_available()})如果成功输出版本信息且无报错则环境准备就绪。3. 核心概念聚焦LSTM 为何能缓解梯度问题在动手写代码前我们需要理解为什么选择 LSTM 作为第一个实战模型。这涉及到 RNN 的一个经典难题梯度消失/爆炸。通俗理解想象你要训练一个模型理解一段话。RNN 就像一个人逐字阅读每读一个新字他都会结合刚读的字来更新自己的理解。但当这段话很长时比如100个字最早读的那些字对当前理解的影响就会变得微乎其微梯度消失或者影响被异常放大梯度爆炸。这导致模型无法学习长距离的依赖关系。LSTM 的解决方案LSTM长短期记忆网络在 RNN 的基础上引入了“细胞状态”和三个“门控机制”。细胞状态像一条传送带贯穿整个序列可以相对稳定地传递信息。遗忘门决定从细胞状态中丢弃哪些旧信息。输入门决定将哪些新信息存入细胞状态。输出门基于当前的细胞状态决定输出什么。你可以把 LSTM 单元想象成一个有“记忆”的决策单元。它不会被动地让所有信息随时间衰减而是主动地选择“记住什么”、“忘记什么”、“输出什么”。正是这种精密的门控设计使得它能够有效地捕捉长序列中的依赖关系缓解了普通 RNN 的梯度问题。理解了这一点再看代码中的nn.LSTM模块你就知道它内部在忙活些什么了。4. 实战项目基于 LSTM 的文本情感分类我们将使用经典的 IMDB 电影评论数据集构建一个二分类模型正面/负面评价。这个项目麻雀虽小五脏俱全涵盖了 NLP 任务的标准流程。4.1 数据加载与预处理首先我们使用 torchtext 加载并预处理 IMDB 数据集。torchtext 帮我们完成了下载、分词、构建词汇表等繁琐工作。import torch from torchtext.datasets import IMDB from torchtext.data.utils import get_tokenizer from torchtext.vocab import build_vocab_from_iterator from torch.utils.data import DataLoader from torch import nn import time # 1. 定义分词器使用基本的分词器 tokenizer get_tokenizer(basic_english) # 2. 定义数据迭代器并构建词汇表 def yield_tokens(data_iter): for _, text in data_iter: yield tokenizer(text) # 加载训练集 print(正在加载 IMDB 数据集并构建词汇表...) train_iter IMDB(splittrain) # 构建词汇表设置最大词汇量并添加特殊标记 vocab build_vocab_from_iterator(yield_tokens(train_iter), specials[unk, pad, bos, eos]) vocab.set_default_index(vocab[unk]) # 设置默认索引遇到未知词用unk代替 print(f词汇表大小: {len(vocab)}) # 3. 文本转换管道将文本字符串转换为词汇索引的Tensor text_pipeline lambda x: [vocab[token] for token in tokenizer(x)] label_pipeline lambda x: 1 if x pos else 0 # 4. 数据批处理函数 def collate_batch(batch): label_list, text_list, text_lengths [], [], [] for (_label, _text) in batch: label_list.append(label_pipeline(_label)) processed_text torch.tensor(text_pipeline(_text), dtypetorch.int64) text_list.append(processed_text) text_lengths.append(processed_text.size(0)) # 对文本进行填充使一个batch内的序列长度一致 text_list nn.utils.rnn.pad_sequence(text_list, padding_valuevocab[pad], batch_firstTrue) label_list torch.tensor(label_list, dtypetorch.int64) text_lengths torch.tensor(text_lengths, dtypetorch.int64) # 对文本长度进行排序后续 pack_padded_sequence 需要 text_lengths, perm_idx text_lengths.sort(descendingTrue) text_list text_list[perm_idx] label_list label_list[perm_idx] return label_list, text_list, text_lengths # 5. 创建 DataLoader BATCH_SIZE 64 train_iter IMDB(splittrain) # 重新获取迭代器 train_dataloader DataLoader(list(train_iter), batch_sizeBATCH_SIZE, shuffleTrue, collate_fncollate_batch) # 取一个批次看看形状 for labels, texts, lengths in train_dataloader: print(f标签批次形状: {labels.shape}) # torch.Size([64]) print(f文本批次形状: {texts.shape}) # torch.Size([64, 最大序列长度]) print(f长度批次形状: {lengths.shape}) # torch.Size([64]) break关键点解析vocab将单词映射为数字索引的字典是文本进入模型前的必要步骤。collate_batch这是DataLoader的核心。因为每个评论长度不同我们需要用pad将它们填充到同一长度pad_sequence并记录原始长度。对长度排序是为了后续 LSTM 使用pack_padded_sequence提高计算效率。DataLoaderPyTorch 的数据加载器负责批量生成数据并自动打乱。4.2 构建 LSTM 模型现在我们来定义模型。一个典型的用于文本分类的 LSTM 网络包含以下几个部分嵌入层将单词索引转换为密集向量。LSTM 层核心序列处理层。全连接层将 LSTM 的输出映射到分类结果。class LSTMModel(nn.Module): def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim, n_layers, dropout_rate, pad_idx): super().__init__() # 嵌入层 self.embedding nn.Embedding(vocab_size, embed_dim, padding_idxpad_idx) # LSTM层 self.lstm nn.LSTM(embed_dim, hidden_dim, num_layersn_layers, bidirectionalFalse, # 先使用单向LSTM batch_firstTrue, dropoutdropout_rate if n_layers 1 else 0) # 多层时使用dropout # 全连接层 self.fc nn.Linear(hidden_dim, output_dim) # Dropout层 self.dropout nn.Dropout(dropout_rate) def forward(self, text, text_lengths): # text shape: [batch_size, seq_len] # 1. 通过嵌入层 embedded self.dropout(self.embedding(text)) # shape: [batch_size, seq_len, embed_dim] # 2. 打包序列提高LSTM效率 packed_embedded nn.utils.rnn.pack_padded_sequence(embedded, text_lengths.cpu(), batch_firstTrue, enforce_sortedTrue) packed_output, (hidden, cell) self.lstm(packed_embedded) # hidden shape: [num_layers * num_directions, batch_size, hidden_dim] # 3. 取最后一层的隐藏状态作为序列的表示 # 我们使用的是单向LSTM所以 hidden[-1, :, :] 就是最后一个时间步的隐藏状态 hidden self.dropout(hidden[-1, :, :]) # shape: [batch_size, hidden_dim] # 4. 通过全连接层输出 output self.fc(hidden) # shape: [batch_size, output_dim] return output # 模型参数 VOCAB_SIZE len(vocab) EMBED_DIM 100 HIDDEN_DIM 256 OUTPUT_DIM 2 # 正面/负面 N_LAYERS 2 DROPOUT_RATE 0.5 PAD_IDX vocab[pad] # 实例化模型 model LSTMModel(VOCAB_SIZE, EMBED_DIM, HIDDEN_DIM, OUTPUT_DIM, N_LAYERS, DROPOUT_RATE, PAD_IDX) print(model)代码精讲nn.Embedding这是 NLP 的标配。它将每个单词索引一个整数映射为一个固定长度的向量embed_dim维。这个向量会在训练过程中被优化可以理解为模型学到的“单词含义”。pack_padded_sequence这是处理变长序列的关键技巧。它告诉 LSTM 哪些位置是填充的从而避免在填充部分进行无意义的计算能显著提升训练速度。hidden[-1, :, :]LSTM 会输出所有时间步的隐藏状态但对于分类任务我们通常只关心序列整体的语义。这里我们取最后一层 LSTM 的最后一个有效时间步的隐藏状态通过pack_padded_sequence处理hidden的最后一维已经对应了序列的末尾作为整个句子的向量表示。Dropout一种正则化技术随机“关闭”一部分神经元防止模型过拟合。在嵌入层后和全连接层前使用效果较好。4.3 定义损失函数与优化器模型定义好后我们需要告诉它如何学习优化器以及学得好不好损失函数。# 定义损失函数和优化器 import torch.optim as optim # 损失函数交叉熵损失适用于分类问题 criterion nn.CrossEntropyLoss() # 优化器Adam自适应学习率非常常用 optimizer optim.Adam(model.parameters(), lr1e-3) # 将模型移动到GPU如果可用 device torch.device(cuda if torch.cuda.is_available() else cpu) model model.to(device) criterion criterion.to(device) print(f使用设备: {device})关键概念nn.CrossEntropyLoss()分类任务的标准损失函数。它内部已经包含了 Softmax 操作所以模型最后一层不需要再加 Softmax。optim.Adam当前最流行的优化器之一相比传统的 SGD它能为每个参数计算自适应学习率收敛更快更稳。lr1e-3是一个常用的初始学习率。4.4 训练与验证循环这是整个流程的核心我们将实现一个标准的训练 epoch 和一个评估 epoch。def train_epoch(model, dataloader, criterion, optimizer, device): model.train() # 切换到训练模式启用Dropout等 epoch_loss 0 epoch_acc 0 for batch_idx, (labels, texts, lengths) in enumerate(dataloader): # 将数据移动到设备 labels labels.to(device) texts texts.to(device) lengths lengths.to(device) # 1. 梯度清零 optimizer.zero_grad() # 2. 前向传播 predictions model(texts, lengths).squeeze(1) # 3. 计算损失 loss criterion(predictions, labels) # 4. 计算准确率 acc calculate_accuracy(predictions, labels) # 5. 反向传播 loss.backward() # 6. 更新参数 optimizer.step() epoch_loss loss.item() epoch_acc acc.item() # 每处理一定批次打印一次进度 if batch_idx % 50 0: print(f Batch {batch_idx}/{len(dataloader)}, Loss: {loss.item():.4f}, Acc: {acc.item():.4f}) return epoch_loss / len(dataloader), epoch_acc / len(dataloader) def evaluate(model, dataloader, criterion, device): model.eval() # 切换到评估模式关闭Dropout等 epoch_loss 0 epoch_acc 0 with torch.no_grad(): # 关闭梯度计算节省内存和计算 for labels, texts, lengths in dataloader: labels labels.to(device) texts texts.to(device) lengths lengths.to(device) predictions model(texts, lengths).squeeze(1) loss criterion(predictions, labels) acc calculate_accuracy(predictions, labels) epoch_loss loss.item() epoch_acc acc.item() return epoch_loss / len(dataloader), epoch_acc / len(dataloader) def calculate_accuracy(preds, y): 计算准确率 # preds shape: [batch_size, output_dim] # y shape: [batch_size] _, predicted torch.max(preds, dim1) # 取概率最大的类别 correct (predicted y).float() acc correct.sum() / len(correct) return acc # 准备验证集 valid_iter IMDB(splittest) valid_dataloader DataLoader(list(valid_iter), batch_sizeBATCH_SIZE, shuffleFalse, collate_fncollate_batch) # 开始训练 N_EPOCHS 5 print(开始训练...) for epoch in range(N_EPOCHS): start_time time.time() train_loss, train_acc train_epoch(model, train_dataloader, criterion, optimizer, device) valid_loss, valid_acc evaluate(model, valid_dataloader, criterion, device) end_time time.time() epoch_mins, epoch_secs divmod(end_time - start_time, 60) print(fEpoch: {epoch1:02} | Time: {epoch_mins:.0f}m {epoch_secs:.0f}s) print(f\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc*100:.2f}%) print(f\t Val. Loss: {valid_loss:.3f} | Val. Acc: {valid_acc*100:.2f}%)运行结果与解读 运行上述代码你会看到类似下面的输出具体数值会因随机性而不同开始训练... Batch 0/391, Loss: 0.6931, Acc: 0.5000 Batch 50/391, Loss: 0.6321, Acc: 0.6562 ... Epoch: 01 | Time: 2m 30s Train Loss: 0.512 | Train Acc: 74.32% Val. Loss: 0.432 | Val. Acc: 80.15% ... Epoch: 05 | Time: 2m 25s Train Loss: 0.285 | Train Acc: 88.91% Val. Loss: 0.318 | Val. Acc: 86.74%这意味着什么Loss损失衡量模型预测与真实标签的差距越低越好。训练 Loss 持续下降说明模型在学习。Accuracy准确率预测正确的比例。在 IMDB 二分类任务上一个简单的 LSTM 模型在 5 个 epoch 后能达到86%的验证集准确率这已经是一个不错的结果证明了模型的有效性。关键观察验证集准确率Val. Acc与训练集准确率Train Acc相差不大说明模型没有严重过拟合。如果 Train Acc 远高于 Val. Acc则需要考虑增加 Dropout、降低模型复杂度或获取更多数据。5. 模型推理用训练好的模型预测新评论训练完成后我们可以保存模型并用于预测新的电影评论。def predict_sentiment(model, sentence, vocab, tokenizer, device, max_length500): 预测单条文本的情感 model.eval() # 文本预处理 tokenized tokenizer(sentence) if len(tokenized) max_length: tokenized tokenized[:max_length] # 截断过长的句子 indexed [vocab[t] for t in tokenized] tensor torch.LongTensor(indexed).unsqueeze(0).to(device) # shape: [1, seq_len] length_tensor torch.LongTensor([len(indexed)]).to(device) with torch.no_grad(): prediction model(tensor, length_tensor) # 获取概率 probabilities torch.softmax(prediction, dim1) # 获取预测类别 _, predicted_class torch.max(prediction, dim1) sentiment 正面 if predicted_class.item() 1 else 负面 confidence probabilities[0][predicted_class.item()].item() return sentiment, confidence # 测试几个例子 test_sentences [ This movie is fantastic! The acting was great and the plot was engaging., A terrible waste of time. Boring and poorly acted., It was okay, not as good as I expected but had some funny moments. ] print(\n--- 模型预测测试 ---) for sent in test_sentences: sentiment, confidence predict_sentiment(model, sent, vocab, tokenizer, device) print(f评论: \{sent[:50]}...\) print(f 预测情感: {sentiment} (置信度: {confidence:.2%})) print()6. 从 LSTM 到 Transformer 与 BERT技术演进与选择跑通了 LSTM 项目你现在已经掌握了 NLP 建模的完整流程数据处理、词嵌入、序列模型、训练、评估。这是理解一切更高级模型的基础。那么LSTM、Transformer、BERT 和 LLM 到底是什么关系我们该如何选择1. LSTM (及其变体 GRU)核心价值序列建模的经典方法结构相对简单参数量小在小数据集或对序列顺序极其敏感的任务上仍有优势。适用场景中等长度文本分类、时间序列预测、作为复杂模型的子模块。本文位置作为理解序列建模的“教学模型”。2. Transformer核心突破完全基于“自注意力”机制摒弃了 RNN 的循环结构实现了高度的并行化极大地提升了训练效率并能更好地建模长距离依赖。与 LSTM 的关键区别LSTM 是“串行”处理Transformer 是“并行”处理。Transformer 的注意力机制让每个词都能直接与句子中所有其他词建立联系无论距离多远。适用场景几乎所有现代 NLP 任务的基石架构尤其是机器翻译、文本生成、长文档理解。3. BERT本质是基于 Transformer 编码器部分在海量语料上通过“掩码语言模型”和“下一句预测”任务进行预训练得到的模型。给你的价值你不需要从零开始训练一个 Transformer。你可以下载预训练好的 BERT在其强大的通用语言表征基础上用你的少量业务数据如几千条评论进行“微调”就能快速得到一个高性能的专业模型。这被称为“迁移学习”。操作变化在代码层面你需要将nn.LSTM换成transformers.BertModel并在其输出后接一个分类头。数据处理部分也需要使用 BERT 对应的分词器。4. LLM (大语言模型)本质通常是基于 Transformer 解码器部分在超大规模数据和算力上训练出的巨型模型如 GPT、LLaMA。给你的选择调用 API对于大多数应用直接调用 OpenAI、文心一言等提供的 API 是最快的方式。本地部署与微调对于有隐私、成本或定制化需求的场景可以下载开源 LLM如 LLaMA 3在自己的领域数据上进行“指令微调”或“全参数微调”。这需要强大的 GPU 资源和更复杂的工程技巧。选择建议入门/教学/轻量级任务从LSTM开始理解本质。需要快速获得高精度使用BERT等预训练模型进行微调。需要生成文本、对话、复杂推理考虑使用或微调LLM。研究或定制化架构深入理解Transformer并自己实现或修改。7. 常见问题与排查思路在实践过程中你几乎一定会遇到下面这些问题。这里提供一个快速排查指南。问题现象可能原因排查方式解决方案Loss 为 NaN 或突然变得巨大1. 学习率过高。2. 梯度爆炸。3. 数据中存在异常值如 None。1. 打印每个 batch 的 loss看是何时出现的。2. 检查数据预处理流程确保输入中没有非数值。1. 大幅降低学习率如1e-4。2. 使用梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0)。3. 在数据管道中添加健壮性检查。准确率始终在 50% 左右二分类模型没有学习可能处于随机猜测状态。1. 检查数据标签是否正确加载打印几个样本看看。2. 检查损失函数和模型输出维度是否匹配。3. 检查优化器是否生效参数是否在更新。1. 确保label_pipeline函数正确。2. 确保OUTPUT_DIM与类别数一致且损失函数正确。3. 尝试更小的模型或简化任务先确保 pipeline 通畅。训练速度非常慢1. 未使用pack_padded_sequence。2. Batch size 太小。3. 未使用 GPU。1. 检查collate_batch函数和模型forward中是否正确处理了变长序列。2. 在内存允许下增大BATCH_SIZE。3. 检查model.to(device)和data.to(device)。1. 务必使用pack_padded_sequence。2. 调整BATCH_SIZE到 32、64 或 128。3. 确认 CUDA 可用并使用.cuda()或.to(device)。验证集准确率远低于训练集模型过拟合。观察训练和验证 loss/acc 曲线看是否训练集指标持续下降而验证集指标停滞或上升。1. 增加 Dropout 比率。2. 在 LSTM 层后添加更多的 Dropout。3. 使用 L2 权重衰减optim.Adam(..., weight_decay1e-5)。4. 获取更多训练数据或使用数据增强。RuntimeError: CUDA out of memoryGPU 内存不足。尝试减小BATCH_SIZE。1. 将BATCH_SIZE减半如 64-32。2. 使用梯度累积多次前向传播后再更新一次参数。3. 使用混合精度训练 (torch.cuda.amp)。8. 最佳实践与工程建议当你掌握了基础流程后下面这些建议能让你的项目更加稳健和专业。1. 数据预处理是重中之重文本清洗去除 HTML 标签、特殊字符、统一大小写。分词对于英文basic_english分词器足够入门。对于中文需要专门的分词工具如 jieba或基于字的分词。词汇表考虑设置最大词汇量过滤掉出现频率过低的词以控制模型大小。2. 模型调试技巧超参数调优EMBED_DIM100-300、HIDDEN_DIM128-512、N_LAYERS1-3、DROPOUT_RATE0.3-0.7和学习率是需要重点调节的。建议使用网格搜索或随机搜索但先从本文的默认值开始。监控训练过程使用 TensorBoard 或 WandB 记录 loss 和 accuracy 曲线直观判断模型状态。3. 项目结构规范化your_nlp_project/ ├── data/ # 存放原始和处理后的数据 ├── src/ │ ├── data_loader.py # 数据加载与预处理模块 │ ├── model.py # 模型定义 │ ├── train.py # 训练脚本 │ └── predict.py # 推理脚本 ├── configs/ # 配置文件超参数 ├── saved_models/ # 保存训练好的模型 ├── requirements.txt # 项目依赖 └── README.md # 项目说明4. 迈向下一步用 BERT 升级你的项目当你用 LSTM 跑通流程后升级到 BERT 会非常顺畅。主要改动点安装transformers库pip install transformers将分词器换成BertTokenizer.from_pretrained(bert-base-uncased)将模型换成BertModel.from_pretrained(bert-base-uncased)并在其输出上添加分类头。训练时通常只需要微调最后几层可以冻结 BERT 的前面层以加快训练。通过这个 LSTM 实战项目你不仅学会了一个可运行的模型更重要的是掌握了 NLP 从数据到结果的完整工作流。这个工作流是通用的无论是面对 Transformer、BERT 还是未来的新模型你都知道该如何入手处理数据、构建模型、定义损失、训练优化、评估验证。下一步我建议你尝试用相同的 IMDB 数据集但将模型替换为 BERT亲身体验一下预训练模型带来的性能提升和便捷性。你会发现很多底层流程是相通的变化的只是模型模块和分词方式。这才是学习 NLP 最有效率的方式掌握不变的模式去拥抱万变的技术。