char-rnn
Andrej Karpathy 用 Torch/Lua 从零实现的多层 RNN 字符级语言模型教学项
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
Andrej Karpathy 用 Torch/Lua 从零实现的多层 RNN 字符级语言模型教学项
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
2015年,彼时的深度学习江湖还是 CNN 和语音识别的天下,一个叫 Andrej Karpathy(现任特斯拉 AI 总监、OpenAI 联合创始人)的斯坦福博士生,在个人博客上写了一篇后来被业界奉为 RNN 入门必读的文章——"The Unreasonable Effectiveness of Recurrent Neural Networks"。他用一个不到 500 行的 Python/numpy 脚本演示了 RNN 生成莎士比亚剧本、Linux 内核代码甚至手写笔记的能力,震惊四座。
char-rnn(Character-level Recurrent Neural Networks)正是这篇博文背后代码的正式实现,由 Torch/Lua 编写,用于从零训练字符级语言模型——喂给模型一段文本,它学会预测下一个最可能出现的字符,然后用学到的「文字直觉」一个字一个字地续写内容。这听起来简单,但背后是完整的多层 RNN 实现(LSTM、GRU、Vanilla RNN 三种架构可选),以及 GPU 加速、梯度裁剪、学习率衰减、Dropout 正则化等现代训练技巧。
char-rnn 的代码结构非常清晰,全工程只有 9 个文件,但模块化程度极高:
char-rnn/
├── train.lua # 训练主程序
├── sample.lua # 推理/采样程序
├── model/
│ ├── LSTM.lua # 长短期记忆网络
│ ├── GRU.lua # 门控循环单元
│ └── RNN.lua # 基础循环神经网络
├── util/
│ ├── CharSplitLMMinibatchLoader.lua # 数据批处理加载器
│ ├── OneHot.lua # 字符One-Hot编码
│ ├── model_utils.lua # 模型克隆与序列化工具
│ └── misc.lua # 通用工具函数
└── data/ # 数据目录(放 input.txt)
model/LSTM.lua 是核心,包含了完整的 LSTM 前向传播与反向梯度计算。LSTM 通过输入门、遗忘门、输出门和细胞状态的精心设计,解决了传统 RNN 的梯度消失问题,让模型能够捕捉长距离依赖关系——比如在一段对话中记住上文的主题。util/CharSplitLMMinibatchLoader.lua 则负责将原始文本切分成 mini-batch,支持任意长度的序列,并自动完成训练/验证/测试集划分。
train.lua 提供了丰富的命令行参数:-rnn_size(隐藏层维度,默认128)、-num_layers(层数,默认2)、-seq_length(反向传播展开步数,默认50)、-learning_rate(学习率,默认2e-3)、-dropout(正则化)等。默认使用 RMSProp 优化器,配合梯度裁剪(-grad_clip 5)防止梯度爆炸。
安装门槛不低。char-rnn 依赖 Torch 框架——一个彼时在学术圈流行、但如今已被 PyTorch 完全取代的 Lua 深度学习库。Torch 的安装需要从源码克隆整个 distro 仓库,并通过 install-deps 脚本安装 GCC、CMake、Git 等系统依赖。对于没有 GPU 的用户,安装纯 CPU 版本即可;NVIDIA GPU 用户则需要额外安装 CUDA Toolkit 并通过 LuaRocks 安装 cutorch 和 cunn 包,实测可比 CPU 快约 15 倍。整个安装过程在良好的网络环境下大约需要 30 分钟到 2 小时,对新手不太友好。
训练流程极为简单。将文本文件(如莎士比亚剧本)放入 data/tinyshakespeare/input.txt,运行:
th train.lua -data_dir data/tinyshakespeare
模型会自动划分训练集(95%)和验证集(5%),每 1000 步在验证集上评估困惑度(Perplexity),并将检查点保存到 cv/ 目录。训练完成后用 sample.lua 生成文本:
th sample.lua -checkpoint cv/lstm.t7
生成结果令人着迷——模型不仅学会了莎士比亚的用词习惯,甚至连标点、断行、人物对白的格式都模仿得惟妙惟肖。Karpathy 在博客中展示了用 Linux 内核源码训练的模型,生成出来的「代码」在语法层面几乎可以骗过普通程序员。
char-rnn 的更大意义在于它间接催生了 PyTorch。Karpathy 在特斯拉和 OpenAI 期间积累了深厚的 PyTorch 使用经验,而 PyTorch 的早期核心作者 Soumith Chintala 正是 Torch 团队的核心成员。char-rnn 所代表的「动态计算图 + 简洁代码风格」理念,被完整继承到了 PyTorch 的设计哲学中。某种意义上,char-rnn 是 PyTorch 时代的序章。
值得注意的是,Justin Johnson(斯坦福 CS231n 课程讲师)随后用更干净的 Torch 代码重写了 char-rnn,发布为 torch-rnn,并建议直接使用该版本——torch-rnn 使用 Adam 优化器、硬编码 RNN/LSTM 前反向传播以提升效率,并解决了原版中模型克隆导致的诸多问题。但 torch-rnn 本身也已被弃用,PyTorch 时代的推荐方案是直接使用 torch.nn.LSTM 或更现代的 torch.nn.Transformer。
char-rnn 在 2016 年后被大量更现代的框架超越:
尽管如此,char-rnn 仍是理解 RNN/LSTM 原理的绝佳教学工具,代码量小(每个模型文件约 200 行)、逻辑清晰、没有现代框架的复杂性遮挡本质。对于想深入理解序列建模梯度流、隐藏状态的含义、字符级建模的特殊挑战(如 OOV 问题),char-rnn 依然是不可替代的起点。
char-rnn 是 Andrej Karpathy 为普及 RNN 原理而写的教学级实现,用 Lua/Torch 从零构建了字符级语言模型的完整训练流程,是深度学习入门者和 NLP 历史研究者的必读项目——尽管技术栈已过时,但其代码结构和设计思路在今天依然有很高的学习价值。