
神经网络:从感知机到深度学习
一层层简单函数如何学会复杂的模式
那一手没人看懂的棋
2016 年 3 月 10 日,在首尔五番棋的第二局,一台名叫 AlphaGo 的机器把一颗黑子下在了棋盘的第五线上。这一手太过古怪,连人类解说都以为是失误。一位职业棋手当场说,初学者要是这么下棋是要被骂的。李世石——这位 18 次拿过围棋世界冠军的棋手——站起身离开了房间,去平复心绪。
那并不是失误。五十手之后,这颗子——如今因「第 37 手」而闻名——成了整盘棋赖以转折的关键。AlphaGo 赢了。被视为当世最伟大棋手之一的李世石,以 4–1 输掉了这个系列赛。而真正要紧的地方在于:没有任何人类教过 AlphaGo 下这一手。它不在任何棋谱里。这台机器是靠自己摸索出来的——通过和自己对弈数百万局,并不断微调数十亿个细小的内部数字,直到一种从没有人见过的模式浮现出来。
围棋的可能局面数量,比可观测宇宙里的原子还多。你没法用暴力穷举来破解它。你也没法把它的规则一条条写下来。要想以超越人类的水平下围棋,唯一的办法就是去学它——而做这件「学习」之事的,正是一个神经网络:一摞简单的数学单元,只要给它足够的数据、足够多的调整,它就能找到连人类都无法完全说清的结构。
同样的这套机制——同样的加权求和、同样的训练循环、同样的梯度微调——正是驱动你正在对话的语言模型、为可疑刷卡交易打标记的系统,以及量化基金如今对准金融市场的那些模型的东西。这节课要讲的,就是那只「黑盒子」内部究竟在发生什么。
感知机:一切的起点
每一个神经网络——从简单的垃圾邮件过滤器,到 GPT,再到 AlphaGo——都源自同一个想法:感知机,由 Frank Rosenblatt 在 1958 年发明。它是一个大致受生物神经元启发的数学模型。真实的神经元通过树突接收电信号,在细胞体里把它们累加起来,只有当合并后的输入越过某个阈值时,才会沿轴突发出一个信号。感知机做的是同一件事,只不过用的是数字而不是电压。
感知机接收一个输入向量 x,把每个输入乘以一个习得的权重 w,把这些乘积加起来,再加上一个用来移动阈值的偏置项 b,然后把结果送进一个激活函数。如果结果过了线,这个神经元就「激活」;否则它就保持沉默。整件事就是一个紧凑的表达式:output = f(w·x + b)。
可以把权重想象成一个个音量旋钮。每个输入到来时都带着某种响度,而权重决定了这个输入对这个特定神经元到底有多重要。一个正在学着识别欺诈交易的神经元,可能会把「交易金额相对于账户历史的比例」这一项的权重拧大,把「一天中的时段」这一项的权重拧小。学习,归根结底,无非就是把那些旋钮调到正确的位置——并没有更玄乎的东西。
单个感知机有一个硬性局限:它只能用一条直线来分隔数据(或者在更高维度里,用一个平的超平面)。它能回答「这个点在线的上方还是下方?」,却答不出「这个点是不是在那块弯曲的区域里?」。经典的例子是 XOR 问题——一种已被证明单个感知机学不会的模式,正是这个局限,在 1970 年代帮着把 AI 的经费冻结了好些年。而破解之道,事后看来简单得几乎荒谬:把许多感知机堆叠成一层层,并在它们之间插入一个非线性的激活。这样一来,得到的网络就能弯折、折叠,把空间切割成任意复杂的形状。
层、深度,以及为什么叫「深度」学习
一个神经元是一个旋钮。一个有用的网络则是成千上万个旋钮,被组织成一层层层,像接力传水桶那样把信息往前传递。
- 输入层——你的原始特征进入的地方:一张图像的像素、一句话里的词,或者对一个交易模型而言,是价格、成交量、波动率、订单簿失衡这类东西。
- 隐藏层——夹在中间的那些层,真正干活的地方。每一层接过上一层的输出,把它们重新组合成新的、更抽象的特征。
- 输出层——最终的答案:一个概率、一个价格预测、一个类别标签。
深度学习里的「深」这个字,意思很简单,就是很多隐藏层。而深度给你换来一样很具体的东西:一套特征的层级结构。在一个图像网络里,第一层检测边缘,下一层把边缘拼成形状,再下一层把形状拼成物体。没人去编写过「边缘检测器」或「眼睛检测器」——这些概念是从训练中涌现出来的。网络发明了属于它自己的中间词汇。
这里有一个很漂亮的理论结果,叫通用逼近定理:哪怕只有一个隐藏层的网络,只要神经元够多,就能以任意精度逼近任何连续函数。换句话说,合适的网络在原理上能表示你数据里存在的任何模式。但有个陷阱——而且是个大陷阱——就是「在原理上」这几个字承担了太多分量。这条定理保证这样的网络存在;它对你能不能找到它、你有没有足够数据把它钉死、乃至你追的那个模式到底是不是真的,统统什么都没说。在金融这种低信号的领域里,「可被表示」和「可被学到」之间的那道鸿沟,正是绝大多数模型走向死亡的地方。
激活函数:那一勺非线性的秘制酱料
有一个事实会让人吃惊:没有激活函数,深度一文不值。如果每一层都只是普通的加权求和,那么把十层堆起来,在数学上就和单单一层完全一样——一连串线性运算会塌缩成一个线性运算。你会花掉一大笔算力,只换来一条被吹得天花乱坠的直线。激活函数就是插在层与层之间的那个非线性折点,它让网络得以弯折,而弯折正是让它变强的东西。
每个从业者都该知道的几种激活函数:
- Sigmoid——σ(x) = 1/(1+e⁻ˣ)。把任意输入挤进 (0, 1),这很自然地可以读作一个概率。用作二分类输出很好,但放在隐藏层里就是个糟糕的选择:对于很大的正输入或负输入,曲线会变平,它的梯度趋近于零,学习就此停摆——这就是梯度消失问题。
- Tanh——输出落在 (−1, 1),而且是零中心的,这有助于优化。它在两端仍会饱和,但没有 sigmoid 那么严重。
- ReLU——f(x) = max(0, x)。隐藏层的现代默认选择。它简单得可笑,计算便宜,并且对所有正输入都保持一个健康的梯度。它的毛病是「ReLU 死亡」:一个被推到永远输出零的神经元,可能会变得永久失活。
- Leaky ReLU——f(x) = max(0.01x, x)。对负值放一小股梯度涓流过去,让神经元不至于死掉。
- GELU——ReLU 的一个平滑、带概率味道的近亲,是 BERT、GPT 这类 transformer 内部的标准选择。
反向传播与梯度下降:网络是怎么学的
到目前为止,我们有了一个塞满权重的网络。但那些正确的权重取值是从哪儿来的?没有人把它们一个个敲进去——它们有数百万个。它们是通过一个反馈循环被找出来的,这个循环本质上就是有条理的反复试错,外加微积分在旁边帮着记账。
第一步是前向传播:喂进一个样本,让它流经各层,读出一个预测。第二步是用一个损失函数来衡量那个预测错得有多离谱。对于预测一个数字(比如价格),均方误差取的是预测与真值之差的平方的平均。对于分类,交叉熵衡量的是预测出来的概率离正确答案有多远。损失高意味着「错得很厉害」;训练的全部目标,就是把这个数字往下压。
第三步是巧妙的部分:反向传播。利用微积分里的链式法则,这个算法从损失出发,反着穿过每一层,为每一个单独的权重算出一个梯度——也就是「如果我把这一个权重往上拨那么一丁点,误差是会上升还是下降,幅度有多大?」的答案。正是这个技巧融化了那场「AI 寒冬」。反向传播在 1980 年代被推广开来,让在数百万个权重之间高效地「分摊责任」成为可能,而不必再去瞎猜。
第四步是梯度下降:让每一个权重朝着能减小损失的方向迈一小步,用的规则是 w = w − α × ∂L/∂w。想象你站在一面雾蒙蒙的山坡上,想走到谷底;你看不见底,但你能凭脚下的感觉判断哪边是下坡,于是你朝那个方向迈一步,再重复。学习率 α 就是你的步幅,而它可以说是整个系统里最重要的那个旋钮。太大,你会一步迈过山谷,然后永远在两边来回弹跳;太小,你要么挪上一个世纪,要么在半途陷进某个小坑里出不来。
有两个你马上就会碰到的改进。小批量(Mini-batch):与其在每一个单独样本之后就更新(噪声大),或者只在跑完整个数据集之后才更新(太慢),你在一个小批次之后更新——通常是 32 到 256 个样本——这样既稳定、又对 GPU 友好,是实践中的甜点区。还有 Adam:一个更聪明的优化器,它给每个权重各自一个自适应的步幅,并加入动量来抚平嘈杂的梯度。在几乎任何项目上,Adam 都是个明智的起步默认选择——不过在金融里,由于信噪比很低,你仍然得手工去调学习率、权重衰减和停止的时机。
过拟合:当网络是在死记硬背而不是在学习
这就是那种毁掉的金融模型比任何其他失败模式都多的「死法」。神经网络是个如此灵活的函数拟合器,一旦有机会,它会把你的训练数据干脆背下来——连同所有的随机噪声、一次性的偶然事件,以及那些永远不会重演的巧合,统统背下来。它在见过的数据上得分漂亮,可一遇到任何新东西就当场垮掉。这就是过拟合,而在市场里——真正的信号微弱、噪声却震耳欲聋——它是默认的结局,而不是例外。与之对抗的工具,叫作正则化。
Dropout 是最流行的一个。在每一个训练步里,每个神经元都有一个概率 p(常取 0.2–0.5)被临时关掉。被迫在随机的队友不断消失的情况下还得干活,网络就学会了把自己的知识铺散到许多神经元上,而不是把全部赌注押在少数几个脆弱的神经元上——相当于把一种集成效应烤进了单个模型里。到了预测的时候,所有神经元重新打开,并做适当的缩放。
L1 与 L2 惩罚给损失加上一笔针对大权重的「税」。L2(权重衰减)不鼓励任何单个权重变得太大,把影响力均匀地铺开。L1 则更锋利:它会主动把没用的权重一路逼到恰好为零,等于做了自动的特征选择。在一个你那上百个特征大多是噪声的金融数据集里,L1 能悄悄找出那真正携带信号的少数几个。
批归一化(Batch normalization)把每一层的输出重新缩放到一个稳定的均值和方差,这能让训练更平稳,并允许你用更高的学习率。早停(Early stopping)是所有方法里最简单、也最可靠的一道防线:盯着一个留出的验证集上的误差,一旦它在训练误差还在下降的同时开始往上爬,就停下——那个交叉点,正是网络从「学习模式」切换到「死记噪声」的确切时刻。
用 CNN 抓模式,用 RNN 和 LSTM 处理序列
普通的前馈网络把每一个输入都当成一袋没有结构的数字。但很多真实数据是有结构的——一张图像有空间布局,一段价格序列有时间次序——而有两种专门的架构直接利用了这种结构。
卷积神经网络(CNN)是为图像而生的。CNN 不是把每个像素都连到每个神经元上,而是让一些小滤波器在输入上滑动,搜寻局部的模式——这里一道边缘、那里一片纹理——并在每个位置都复用同一个滤波器。靠前的层捕捉边缘;更深的层把它们拼成形状和物体。在金融里,研究者已经把 CNN 对准了:
- 蜡烛图的图像——把看图这件事重新框定成一个视觉模式识别的任务。
- 订单簿热力图——在市场深度的快照里发现供需失衡。
- 对原始价格序列做一维卷积——像图像 CNN 学习空间花纹那样,去学习短时的时间花纹。
循环神经网络(RNN)是为序列而生的。它们一次处理一个时间步,同时携带一个隐藏状态——一份滚动的记忆——从这一步传到下一步。理论上,这让它们成为处理时间序列的理想之选。但实践中,朴素的 RNN 在长序列上会被梯度消失问题搞瘫:来自很多步以前的信号,在往回走的路上会朝零收缩,于是网络干脆就把遥远的过去忘了。
长短期记忆(LSTM)网络用一小组可学习的门——遗忘门、输入门、输出门——修好了这个问题,它们在每一步决定从记忆里抹掉什么、写进什么、读出什么。这套门控让 LSTM 能把相关信息在好几百步之间一直握住,这也是它成为金融时间序列建模主力的原因——在那里,昨天的一个事件至今仍在撬动今天的价格。
import torch.nn as nn
class PricePredictor(nn.Module):
def __init__(self, input_dim, hidden_dim, num_layers):
super().__init__()
self.lstm = nn.LSTM(input_dim, hidden_dim,
num_layers, batch_first=True,
dropout=0.2)
self.fc = nn.Linear(hidden_dim, 1)
def forward(self, x):
out, _ = self.lstm(x)
return self.fc(out[:, -1, :])
在像 GaiaEx 这样的平台上,WebSocket 数据流持续推送价格和订单簿数据,LSTM 可以很自然地把这个序列吃进去。话虽如此,这个领域已经大半往前走了:transformer——现代语言模型背后的那套架构——如今在许多序列任务上已经追平甚至打败了 LSTM,它靠的是用「注意力」一次性看遍所有时间步,而不是一步步往前走过去。
神经网络修不好的那些问题(尤其是在市场里)
神经网络是出类拔萃的模式发现者。但诚实的教育意味着把它们失灵的地方点出来——而在交易里,它们的失灵代价不菲。
- 哪怕模式根本不存在,它们也会找出模式。给一个深度网络喂噪声,它会自信满满地把噪声拟合下来。市场在很大程度上就是噪声,所以举证的责任在你身上:你得证明一个模式是真实且持久的——而不仅仅是它出现在了去年的数据里。
- 它们是黑盒子。一个模型可以很准,却仍然没法告诉你为什么。当它突然开始亏钱时,往往既没有干净的解释,也没有明摆着的修法。对于承担风险的资金来说,「我不知道它为什么那么干」是一项严重的隐患。
- 它们既贪吃又脆弱。深度学习在拥有数百万条干净样本时才大放异彩。而金融的历史既短、又非平稳、还充满噪声——训练出你这个模型的那个市场状态(regime),完全可能干脆就不复存在了,这个问题叫作分布漂移(distribution shift)。
- 它们没法白白地胜过更简单的模型。在金融里常见的那种表格化、基于特征的数据上,像 XGBoost 这样的梯度提升树常常跑赢神经网络,同时训练更快、也更容易解释。复杂是一项成本,而不是一种美德。
- 它们可以被攻击。对一个输入做出细小而蓄意的扰动,就能把网络的输出翻转过来——这叫对抗样本(adversarial example)——在任何对手能够塑造你的模型所见之物的场合,这都很要紧。
硬件、工具,以及你接下来的路
训练神经网络是算术上的重活——绝大部分是矩阵乘法——而你跑它用的硬件,能把你的迭代速度从「跑一整夜」变成「喝杯咖啡的工夫」。
GPU 是标配。它那成千上万个核心同时对不同的数据跑同一种运算,而这恰恰就是神经网络数学的形状。一个在 CPU 上要爬上 8 小时的模型,在一块现代 GPU 上 15 分钟就能跑完。NVIDIA 占据主导:消费级显卡(RTX 一类的 GPU)拿来学习足够了,而数据中心级显卡(A100、H100)和云实例则负责生产规模的训练。TPU 是 Google 为张量运算定制的芯片,通过 Google Cloud 在超大模型上表现亮眼,但对大多数从业者而言,凭借更广泛的软件支持,GPU 仍是务实的默认之选。
你不必买任何东西就能上手。Google Colab 发放免费的 GPU 时间,拿来学习和做原型绰绰有余;随着你的模型变大,可以按需租用云端 GPU;只有当你已经每天都在训练、而云账单也撑得起这笔开销时,才去买专用硬件。
从这里出发,一条靠谱的学习路径:
- 先用一个普通的前馈网络,搭在少数几个手工设计的特征上——训练快、好调试,也是一个诚实的基准。
- 试试在原始价格序列上跑一个一维 CNN,并和那个基准正面对比一下。
- 搭一个 LSTM,让它吃 GaiaEx API 提供的蜡烛图数据序列。
- 研究注意力和 transformer——它正越来越成为序列任务的首选架构。
- 最重要的是,永远让你的深度模型去和一个像 XGBoost 这样的梯度提升基准较量。如果在你那份表格化的金融数据上,神经网络在样本外连这个更简单的模型都打不过,那就把更简单的那个上线,然后继续往前走。
那个找出了「第 37 手」的循环——预测、衡量误差、微调权重、重复——正是上面这份清单里每一个系统内部都在跑的循环。把那个循环弄明白,你就把深度学习弄明白了;其余的,无非是在它之上的架构和工程。