循环神经网络(一):从预测股票到读懂文字,踏入序列数据的新世界
前面我们学习了多层感知机和卷积神经网络。
多层感知机适合处理表格特征,卷积神经网络适合处理图片。所谓“表格特征”,就是每个样本能用一行固定长度的字段来描述,像 Excel 里的一行数据。
比如房价预测里的面积、楼层、朝向、房龄、地段评分;或风控里的年龄、收入、负债比例、信用评分。这些字段没有先后顺序,拼成一个固定长度的向量就可以直接输入 MLP。
它们有一个共同特点:通常把每个样本当成相对独立的对象来看。
例如:
- 一张猫图和一张狗图,顺序调换后不影响分类;
- 一条房价数据和另一条房价数据,通常可以分别预测;
- 一张手写数字图片,不需要知道上一张图片是什么。
但现实里还有很多数据不能打乱顺序。顺序一变,意思就变了。
- 股票价格:今天的走势会影响明天的判断。
- 语音信号:前一个音节会影响后一个音节的理解。
- 文本句子:“我喜欢你”和“你喜欢我”字一样,顺序不同,意思不同。
- 天气记录:连续几天的温度变化,比某一天单独的温度更有信息。
这些数据有一个共同名字:序列数据(Sequence Data)。
这一篇,我们先不急着讲 RNN,而是先搞懂两件事:
- 序列数据到底特殊在哪里?
- 文本这种人类语言,怎样变成神经网络能处理的数字?
一、什么是序列数据?
序列数据就是一串按顺序排列的数据。
这个顺序通常代表时间、位置或逻辑关系。我们常用下标表示它:
x1, x2, x3, ..., xt
其中 xt 表示第 t 个时间步的数据。
举几个例子:
| 场景 | 一个时间步可能是什么 |
|---|---|
| 股票预测 | 某一天的价格 |
| 天气预测 | 某一天的温度、湿度 |
| 语音识别 | 某一小段声音信号 |
| 文本生成 | 一个字、一个词或一个 token |
序列数据最重要的特点是:
当前数据往往和过去的数据有关。
比如你看到一句话:
我今天晚上想吃
你会自然猜后面可能是“火锅”“面条”“烧烤”,而不太可能是“显卡”。原因不是“吃”这个字单独决定的,而是前面整句话提供了上下文。
二、序列预测:用过去猜未来
序列模型常见任务是:根据前面的内容预测后面的内容。
比如:
已知:x1, x2, x3, ..., xt
预测:x(t+1)
这类模型叫 自回归模型(Autoregressive Model)。名字听起来很学术,其实意思很简单:
用自己过去的历史,预测自己的下一步。
股票预测、天气预测、文本续写都属于这个思路。
1. 最直接的方法:看固定长度的历史
假设我们要预测明天的温度,可以只看过去 3 天:
输入:前3天温度
输出:明天温度
如果写成机器学习任务,它就像普通表格数据:
| 前3天 | 前2天 | 前1天 | 明天 |
|---|---|---|---|
| 20 | 21 | 23 | 24 |
| 21 | 23 | 24 | 22 |
这时用多层感知机也能做,因为我们把过去几天当作几个普通特征输入了。
2. 问题:历史到底看多长?
只看过去 3 天可能不够。文本尤其明显。
比如:
虽然这本书前面铺垫了很多复杂人物关系,但最后真正改变主角命运的人是
想预测下一个词,可能要理解很远之前的人名和情节。固定只看前 3 个词、前 5 个词就不够用了。
于是我们需要一种模型:
它能按顺序读取数据,并且把读过的信息压缩成某种“记忆”。
这就是 RNN 的动机。不过在进入 RNN 之前,我们先处理一个更基础的问题:文字怎么喂给神经网络?
三、机器不认识文字,只认识数字
神经网络本质上做的是矩阵运算。它不能直接理解:
深度学习很好玩
我们必须把文本变成数字。这个过程叫 文本预处理。
一条基本流水线通常包括:
读取文本 -> 词元化 -> 建立词表 -> 转成数字序列 -> 切成小批量
下面一步一步看。
四、词元化:把句子切成小块
词元(Token) 是文本被切分后的基本单位。
词元化就是把一段文本拆成一个个 token。
常见切法有两种。
1. 按词切
英文可以按单词切:
deep learning is fun
切成:
["deep", "learning", "is", "fun"]
优点是语义比较完整;缺点是词表会很大,而且没见过的新词不好处理。
2. 按字符切
中文入门教学里,经常按字切:
深度学习很好玩
切成:
["深", "度", "学", "习", "很", "好", "玩"]
优点是简单、词表小;缺点是单个字的信息有限,需要模型自己从上下文里组合含义。
小白学习 RNN 时,推荐先从字符级文本开始,因为它更容易实现。
五、建立词表:给每个 token 一个编号
切成 token 后,机器还是不认识。我们要给每个 token 分配一个整数编号,这个表叫 词表(Vocabulary)。
比如:
"<unk>" -> 0
"深" -> 1
"度" -> 2
"学" -> 3
"习" -> 4
<unk> 表示未知 token。遇到词表里没有的内容,就统一映射到它。
下面是一份简化版词表代码:
class Vocab:
def __init__(self, tokens):
# 初始化“编号 -> token”的列表,先放一个未知词占位
self.idx_to_token = ['<unk>']
# 初始化“token -> 编号”的字典,未知词的编号固定为 0
self.token_to_idx = {'<unk>': 0}
# 去重并排序,保证编号分配稳定可复现
for token in sorted(set(tokens)):
# 把 token 追加到列表末尾
self.idx_to_token.append(token)
# token 的编号就是它在列表中的位置
self.token_to_idx[token] = len(self.idx_to_token) - 1
def __getitem__(self, tokens):
# 如果输入的是单个 token,直接返回编号
if not isinstance(tokens, (list, tuple)):
# get 的默认值 0 表示词表里没有时返回 <unk>
return self.token_to_idx.get(tokens, 0)
# 如果输入是一组 token,就递归地转换成编号列表
return [self.__getitem__(token) for token in tokens]
def to_tokens(self, indices):
# 如果输入的是单个编号,直接返回对应 token
if not isinstance(indices, (list, tuple)):
return self.idx_to_token[indices]
# 如果输入是一组编号,就逐个转回 token 列表
return [self.idx_to_token[index] for index in indices]
有了词表,文本就可以转换成数字序列:
["深", "度", "学", "习"] -> [1, 2, 3, 4]
注意:这些数字只是编号,不代表大小关系。编号 4 的“习”并不比编号 1 的“深”更大、更重要。
这个细节很重要,下一篇和第三篇会继续用到。
六、把长序列切成训练样本
一本书可能有几十万字,我们不能一次性全部塞进模型。训练时通常会把长文本切成很多小片段。
比如原始序列是:
[1, 2, 3, 4, 5, 6, 7, 8]
如果每次看 4 个 token,可以构造:
输入: [1, 2, 3, 4]
标签: [2, 3, 4, 5]
这是什么意思?
模型读到 1 时,希望预测 2;读到 2 时,希望预测 3;读到 3 时,希望预测 4。
也就是:
每个位置都在练习“根据当前和过去,预测下一个 token”。
生活化例子:
想象你在听一句话:“我今天晚上想吃”。
- 你听到“我”时,会猜下一词可能是“今天”。
- 你听到“我 今天”时,会猜下一词可能是“晚上”。
- 你听到“我 今天 晚上”时,会猜下一词可能是“想吃”。
这就是“输入序列”和“标签序列”错开一位的意义:每个位置都在训练“下一步该接什么”。
1. 随机采样
随机采样就是从长文本中随机抽取片段。
优点:打乱程度高,训练样本更随机。
缺点:相邻批次之间可能没有连续关系,隐状态不方便延续。
这里的“隐状态”可以理解为 RNN 的“短期记忆本”,它保存了上一段序列的上下文信息。如果下一批数据是随机切出来的、和上一批不相邻,那么继续沿用上一批的隐状态就会把“错误的上下文”带进来,反而干扰学习,所以就不方便延续。
2. 顺序分区
顺序分区就是按原文顺序切片。
优点:更符合文本原本顺序,适合让 RNN 的状态连续传递。
缺点:实现时要更注意批量之间的状态管理。
入门阶段,你只要知道:
随机采样更像打散练习题,顺序分区更像按原文一路读下去。
七、小结
这一篇我们为 RNN 打了地基,你需要记住:
- 序列数据的关键是“顺序有意义”,不能随便打乱。
- 自回归模型就是用过去预测未来。
- 文本必须先经过词元化和词表映射,才能变成神经网络能处理的数字。
- token 的整数编号只是身份标记,不代表数值大小。
- 训练语言模型时,常把长文本切成“输入序列”和“向后错一位的标签序列”。
如果用一句话收尾:
RNN 要解决的问题,是让模型一边读序列,一边记住前面发生过什么。
下一篇,我们正式认识 RNN 的核心:隐状态。它就像模型随身携带的一本“短期记忆本”,让机器不再只看当前 token,而能结合前文做判断。
(注:文档部分内容参考《动手学深度学习》)
《动手学深度学习》循环神经网络:https://zh.d2l.ai/chapter_recurrent-neural-networks/index.html
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)