
神經網路:從感知機到深度學習
一層層簡單函式如何學會複雜的模式
那一手沒人看懂的棋
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 手」的迴圈——預測、衡量誤差、微調權重、重複——正是上面這份清單裡每一個系統內部都在跑的迴圈。把那個迴圈弄明白,你就把深度學習弄明白了;其餘的,無非是在它之上的架構和工程。