量化交易中文教材

第 01 章 引言与神经元模型

本章合并原书第 1 章(引言)与第 2 章(神经元模型与网络结构)。第 1 章是历史与背景,压缩成一节;第 2 章确立全书记号,是后面每一章都要用的"语言",需要完全掌握。

学习目标

读完本章,你应当能够:

  1. 用一两句话说清神经网络的发展脉络:McCulloch–Pitts 神经元、感知机与 ADALINE、1969 年后的低潮、Hopfield 网络与反向传播带来的复兴,并知道每个节点在本书哪一章展开。
  2. 写出单输入、多输入神经元的数学模型 \(a=f(\mathbf{W}\mathbf{p}+b)\),说清权值、偏置、净输入、传递函数各自的作用。
  3. 熟记表 2.1 中九种传递函数的定义、值域和典型用途,能根据输出要求选择输出层传递函数。
  4. 写出单层与多层网络的矩阵形式,正确标注每个矩阵和向量的维数,理解权值下标 \(w_{i,j}\)"目标在前、来源在后"的约定。
  5. 根据问题规格确定单层网络的结构,知道多层网络中哪些部分无法由问题直接决定。
  6. 理解延迟、积分器与循环网络的含义,知道它们为什么能表达时间行为。

读前导读

这一章在解决什么问题

结论先说:一个人工神经元,就是一次"线性回归 + 一个非线性开关"。你在 CFA 里见过的多元回归 \(\hat y=b_0+b_1x_1+\cdots+b_kx_k\),在本书里写成 \(n=\mathbf{W}\mathbf{p}+b\):\(\mathbf{p}\) 是自变量(因子),\(\mathbf{W}\) 是回归系数,\(b\) 是截距(本书叫偏置)。区别只在最后一步:回归直接输出 \(n\),神经元把 \(n\) 再送进一个函数 \(f\),比如把它压到 0 到 1 之间当作概率(这就是 logistic 回归),或者只看它的正负给出"买/不买"。取 \(f(n)=n\) 时,神经元就是线性回归。

本章不讲怎么"训练"(即怎么估计系数),只做两件事:一是交代历史,让你知道后面每一章在整个领域中的位置;二是确立全书记号——神经元、一层、多层、循环网络分别怎么写、每个矩阵是什么形状。记号是后面所有推导的语言,这一章的价值主要在这里。

需要先想起来的数学

  • 矩阵乘以向量。\(S\times R\) 矩阵乘以 \(R\times1\) 向量得到 \(S\times1\) 向量,第 \(i\) 个分量是矩阵第 \(i\) 行与向量对应相乘再相加。例:\(\begin{bmatrix}1&2\\3&4\end{bmatrix}\begin{bmatrix}5\\6\end{bmatrix}=\begin{bmatrix}1\cdot5+2\cdot6\\3\cdot5+4\cdot6\end{bmatrix}=\begin{bmatrix}17\\39\end{bmatrix}\)。判断能不能乘,只看"左边的列数 = 右边的行数"。见 第 00 册第 06 章 线性代数速成。
  • 转置。\(\mathbf{p}^T\) 把列向量变成行向量;\([-5\ \ 6]^T\) 是写成一行以节省版面的列向量。
  • 指数函数与函数复合。\(e^{-n}\) 在 \(n\) 很大时趋于 0、在 \(n\) 很负时趋于无穷,所以 \(1/(1+e^{-n})\) 在两端分别趋于 1 和 0。多层网络 \(\mathbf{f}^3(\mathbf{W}^3\mathbf{f}^2(\cdots))\) 是函数套函数,从最里层往外算。见 第 00 册第 04 章 级数与收敛(e 与指数对数部分)。
  • 积分作为"累加"。式 (2.8) 的积分器 \(\int_0^t u(\tau)d\tau\) 可以理解为把输入从 0 到 \(t\) 连续累加,好比把每日现金流累加成期末余额。见 第 00 册第 03 章 积分。

怎么读这一章

1.1 节历史可以快速浏览,记住表格里"哪个节点在哪一章"即可。1.3 和 1.4 节是核心必读,尤其是权值下标约定 \(w_{i,j}\) 和每层矩阵的维数,建议拿纸笔把式 (2.6) 和多层网络的维数自己写一遍。1.4.4 循环网络第一次读只需知道"输出会反馈回输入、网络会随时间演化",细节到第 03、05 章再回头看。1.5 量化实战值得细读,它把结构规则翻译成了因子模型的语言。


1.1 神经网络是什么:背景与历史

1.1.1 从生物神经元到人工神经元

人脑约有 \(10^{11}\) 个神经元,每个神经元约有 \(10^4\) 个连接。一个生物神经元有三个主要部分:

  • 树突(dendrites):树状的接收网络,把电信号送入胞体;
  • 胞体(cell body):对输入信号"求和"并"取阈值";
  • 轴突(axon):一根长纤维,把信号送往其他神经元。

轴突与另一个细胞树突的接触点叫突触(synapse)。神经元的排列方式和突触的强度共同决定了网络的功能。一部分结构是天生的,其余通过学习形成:幼年时主要是建立新连接、淘汰旧连接;成年后主要是改变突触的强弱。原书举了几个例子:幼猫在关键期被剥夺单眼视觉,那只眼睛以后永远无法正常视物;伦敦出租车司机的海马体明显偏大,因为他们要花约两年记忆大量路线。

人工神经网络与生物网络只有两点关键相似:

  1. 基本单元都是高度互联的简单计算单元;
  2. 单元之间的连接决定网络的功能。

所以本书的核心任务可以一句话概括:为特定问题找到合适的连接(权值)。这句话请记住,后面所有的"学习规则""训练算法"都是在回答"怎样找到合适的权值"。

生物神经元很慢(约 \(10^{-3}\) 秒,电路约 \(10^{-10}\) 秒),但大脑依靠大规模并行,在很多任务上比计算机快。人工网络也有并行结构,适合硬件实现,但本书不讨论硬件。

1.1.2 历史:概念与实现交替推动

原书强调技术进步需要两个要素:概念(concept)与实现(implementation)。神经网络的发展是"间歇式跃进",不是平稳演进。下表把历史节点和本书章节对应起来,方便以后查找。

年代 事件 本册章节
1943 McCulloch 与 Pitts 证明人工神经元网络原则上能计算任何算术或逻辑函数,被视为领域起点 第 4 章
1949 Hebb 提出细胞层面的学习机制(Hebb 假设) 第 7 章
1950s 末 Rosenblatt 发明感知机及其学习规则,第一个实际应用(模式识别) 第 4 章
1960 Widrow 与 Hoff 提出 ADALINE 与 LMS(Widrow–Hoff)算法,至今仍在使用 第 10 章
1969 Minsky 与 Papert《Perceptrons》严格指出单层网络的局限,研究停滞约十年 第 4 章
1972 Kohonen、Anderson 各自提出可作记忆的网络(线性联想器、相关矩阵记忆) 第 07、15 章
1976 Grossberg 研究自组织网络,是 ART 的基础 第 18、19 章
1982 Hopfield 用统计力学解释一类可作联想记忆的循环网络 第 03、19 章
1986 Rumelhart 与 McClelland 推广多层网络的反向传播算法,回应了 Minsky–Papert 的批评 第 11 章

1980 年代复兴的另一个原因是"实现":个人计算机和工作站让大规模实验成为可能。这个模式在 2010 年代深度学习兴起时又重演了一次(GPU 与大数据),不过那已超出本书范围。

1.1.3 应用,尤其是金融

原书转引 MATLAB 神经网络工具箱的应用表,覆盖航空、汽车、国防、医疗、油气、语音、电信等行业。与我们相关的三个条目是:

  • 银行:支票读取、信贷申请评估、现金预测、汇率预测、贷款回收率预测、信用风险度量;
  • 金融:房地产估价、按揭筛选、公司债评级、组合交易程序、公司财务分析、货币价格预测;
  • 证券:市场分析、自动债券评级、股票交易建议系统。

最早的商业成功(约 1984 年)是长途电话里的自适应信道均衡器——一个单神经元网络。这说明一件事:有用的网络不一定复杂。在量化研究里,一个设计得当的线性或浅层模型往往比盲目堆叠的深层网络更可靠,这一点我们会在后面的章节反复看到。


1.2 记号约定

神经网络涉及工程、物理、心理、数学多个学科,文献中记号很不统一。原书的约定是:

  • 标量(scalar):小写斜体,\(a,b,c\);
  • 向量(vector):小写粗体,\(\mathbf{a},\mathbf{b},\mathbf{c}\);
  • 矩阵(matrix):大写粗体,\(\mathbf{A},\mathbf{B},\mathbf{C}\)。

本册全程沿用这个约定。还有两条后面会出现的约定,先在这里预告:多层网络用上标表示层号(\(\mathbf{W}^2\) 是第 2 层的权值矩阵,不是平方);训练样本用下标表示序号(\(\mathbf{p}_q\) 是第 \(q\) 个输入)。


1.3 神经元模型

1.3.1 单输入神经元

最简单的神经元只有一个标量输入 \(p\)。它乘以权值(weight)\(w\) 送入求和器;另有一个恒为 1 的输入乘以偏置(bias,也叫 offset)\(b\) 也送入求和器。求和器的输出叫净输入(net input):

\[n = wp + b .\]

净输入经过传递函数(transfer function,也常叫激活函数 activation function)\(f\) 得到输出:

\[a = f(wp+b).\]

与生物神经元对照:\(w\) 对应突触强度,求和与传递函数对应胞体,输出 \(a\) 对应轴突上的信号。

例 \(w=3\),\(p=2\),\(b=-1.5\),则 \(a=f(3\times2-1.5)=f(4.5)\)。实际输出是多少,要看 \(f\) 是什么。

几点要先想清楚:

  • 偏置就是一个输入恒为 1 的权值。这个看法极其有用:第 4 章推导感知机规则、第 7 章用伪逆设计带偏置的网络,都是把偏置并入权值向量、在输入后面补一个 1。不需要偏置时可以省略。
  • \(w\) 与 \(b\) 是可调参数,\(f\) 由设计者选定。所谓"学习",就是用某种规则调整 \(w,b\),让输入/输出关系满足目标。

金融直觉:把单输入神经元和一元回归 \(\hat y=b_0+b_1x\) 对照:\(w\) 是斜率 \(b_1\),\(b\) 是截距 \(b_0\),净输入 \(n\) 就是回归的拟合值。传递函数 \(f\) 是回归里没有的那一步。取 \(f(n)=n\),神经元就是回归本身;取 logsig,就是 logistic 回归(违约概率模型常用的那种);取 hardlim,就是"拟合值大于 0 就买入、否则不买"的交易规则。"学习"对应回归里的"估计系数",只是后面几章用的不一定是最小二乘。

1.3.2 传递函数

传递函数可以是线性的,也可以是非线性的,根据问题的需要选择。最常用的三种:

硬限幅(hard limit,hardlim):

\[a=\mathrm{hardlim}(n)=\begin{cases}0,& n<0\\ 1,& n\ge0\end{cases}\]

用来把输入分成两类,第 4 章大量使用。单输入 hardlim 神经元的输出在 \(p=-b/w\) 处跳变:偏置决定跳变点的位置,权值的符号决定跳变的方向。

推导拆解:跳变发生在净输入由负变非负的地方,即解 \(wp+b=0\),得 \(p=-b/w\)。若 \(w>0\),\(p\) 越大 \(n\) 越大,所以 \(p\ge -b/w\) 时输出 1,"从 0 跳到 1";若 \(w<0\),方向反过来,\(p\) 小的一侧输出 1。例:\(w=2,b=-6\),跳变点 \(p=3\),类似"市盈率因子得分超过 3 才发信号";改成 \(w=-2,b=6\),跳变点仍是 3,但变成"低于 3 才发信号"。

线性(linear,purelin):\(a=n\)。单输入时 \(a\)–\(p\) 图是斜率 \(w\)、截距 \(b\) 的直线。ADALINE(第 10 章)用它。

对数–S 型(log-sigmoid,logsig):

\[a=\frac{1}{1+e^{-n}}\tag{2.2}\]

把整条实轴压缩到 \((0,1)\)。它可微,所以是反向传播训练多层网络(第 11 章)的常用选择。

原书表 2.1 汇总了全书用到的传递函数:

名称 输入/输出关系 MATLAB 名 值域
硬限幅 Hard Limit \(a=0\ (n<0)\);\(a=1\ (n\ge0)\) hardlim \(\{0,1\}\)
对称硬限幅 Symmetrical Hard Limit \(a=-1\ (n<0)\);\(a=+1\ (n\ge0)\) hardlims \(\{-1,1\}\)
线性 Linear \(a=n\) purelin \(\mathbb{R}\)
饱和线性 Saturating Linear \(a=0\ (n<0)\);\(a=n\ (0\le n\le1)\);\(a=1\ (n>1)\) satlin \([0,1]\)
对称饱和线性 Symmetric Saturating Linear \(a=-1\ (n<-1)\);\(a=n\ (-1\le n\le1)\);\(a=1\ (n>1)\) satlins \([-1,1]\)
对数–S 型 Log-Sigmoid \(a=1/(1+e^{-n})\) logsig \((0,1)\)
双曲正切 S 型 Hyperbolic Tangent Sigmoid \(a=(e^n-e^{-n})/(e^n+e^{-n})\) tansig \((-1,1)\)
正线性 Positive Linear \(a=0\ (n<0)\);\(a=n\ (n\ge0)\) poslin \([0,\infty)\)
竞争 Competitive 净输入最大的神经元 \(a=1\),其余 \(a=0\) compet 独热向量

两点补充:

  • poslin 就是今天深度学习里最常用的 ReLU(rectified linear unit)。原书第 3 章 Hamming 网络已经在用它。
  • compet 不是逐元素函数,而是对整层定义的:它要比较层内所有神经元的净输入,选出最大者。今天常用的 softmax 可以看成它的"光滑版"。
  • tansig 与 logsig 只差一个线性变换:\(\tanh(n)=2\,\mathrm{logsig}(2n)-1\)。

推导拆解:验证 \(\tanh(n)=2\,\mathrm{logsig}(2n)-1\) 只需通分。\(2\cdot\frac{1}{1+e^{-2n}}-1=\frac{2-(1+e^{-2n})}{1+e^{-2n}}=\frac{1-e^{-2n}}{1+e^{-2n}}\);分子分母同乘 \(e^{n}\),得 \(\frac{e^n-e^{-n}}{e^n+e^{-n}}=\tanh(n)\)。几何上,tansig 就是把 logsig 横向压缩一半、纵向拉伸两倍再下移 1,值域从 \((0,1)\) 变成 \((-1,1)\)。表中"值域"一列用圆括号 \((0,1)\) 表示取不到端点,方括号 \([0,1]\) 表示能取到;\(\mathbb{R}\) 表示全体实数。

例(原书 P2.1、P2.2) 单输入神经元,\(p=2.0\),\(w=2.3\),\(b=-3\)。净输入 \(n=2.3\times2-3=1.6\)。不指定传递函数就无法确定输出;若取硬限幅,\(a=\mathrm{hardlim}(1.6)=1\);取线性,\(a=1.6\);取对数–S 型,\(a=1/(1+e^{-1.6})=0.8320\)。

1.3.3 多输入神经元

\(R\) 个输入 \(p_1,\dots,p_R\) 分别乘以权值 \(w_{1,1},\dots,w_{1,R}\),加上偏置:

\[n=w_{1,1}p_1+w_{1,2}p_2+\cdots+w_{1,R}p_R+b\tag{2.3}\]

写成矩阵形式(单个神经元时 \(\mathbf{W}\) 只有一行):

\[n=\mathbf{W}\mathbf{p}+b,\qquad a=f(\mathbf{W}\mathbf{p}+b).\tag{2.4–2.5}\]

权值下标约定:\(w_{i,j}\) 的第一个下标是目标神经元(destination),第二个是信号来源(source)。\(w_{1,2}\) 表示"从第 2 个输入到第 1 个神经元"的连接。这个约定让 \(\mathbf{W}\mathbf{p}\) 的矩阵乘法自然成立,务必记牢。

白话解释:为什么"目标在前"就能让矩阵乘法成立?矩阵乘法的规则是"行乘列":\(\mathbf{W}\mathbf{p}\) 的第 \(i\) 个分量是 \(\sum_j w_{i,j}p_j\),即第 \(i\) 行逐个乘以输入的各分量再加总。把第 \(i\) 行解释为"第 \(i\) 个神经元收到的全部权值",求和下标 \(j\) 自然就是"来源"。这和组合收益 \(r_p=\sum_j x_jr_j\) 是同一个结构:一行权重乘一列收益;多个组合并排就是多行,每行一个组合。

简化记号(abbreviated notation):原书画网络图时,把输入向量 \(\mathbf{p}\) 画成一根竖条并标出维数 \(R\times1\),\(\mathbf{W}\) 标 \(1\times R\),\(n\)、\(a\) 标 \(1\times1\)。每个变量都标维数,读者一眼就能看出它是标量、向量还是矩阵。写代码时养成同样的习惯——在注释里写出每个数组的形状——能避免大量 bug。

输入个数由问题的外部规格决定。原书的例子:预测放风筝的条件,输入是气温、风速、湿度,网络就有 3 个输入。

例(原书 P2.3) 两输入神经元,\(\mathbf{W}=[3\ \ 2]\),\(\mathbf{p}=[-5\ \ 6]^T\),\(b=1.2\)。净输入

\[n=3\times(-5)+2\times6+1.2=-1.8 .\]

用对称硬限幅得 \(a=-1\);用饱和线性得 \(a=\mathrm{satlin}(-1.8)=0\);用双曲正切得 \(a=\mathrm{tansig}(-1.8)=-0.9468\)。


1.4 网络结构

1.4.1 一层神经元

把 \(S\) 个神经元并排组成一层,每个输入都连到每个神经元。权值矩阵是 \(S\times R\):

\[\mathbf{W}=\begin{bmatrix}w_{1,1}&w_{1,2}&\cdots&w_{1,R}\\ w_{2,1}&w_{2,2}&\cdots&w_{2,R}\\ \vdots&&&\vdots\\ w_{S,1}&w_{S,2}&\cdots&w_{S,R}\end{bmatrix}\tag{2.6}\]

一层包括权值矩阵、求和器、偏置向量 \(\mathbf{b}\)(\(S\times1\))、传递函数和输出向量 \(\mathbf{a}\)(\(S\times1\)):

\[\mathbf{a}=\mathbf{f}(\mathbf{W}\mathbf{p}+\mathbf{b}).\]

要点:

  • 行下标 = 目标神经元,列下标 = 输入来源。\(\mathbf{W}\) 的第 \(i\) 行就是第 \(i\) 个神经元的全部输入权值。第 4 章会把这一行记作列向量 \({}_i\mathbf{w}\),它在几何上有清楚的含义(决策边界的法向量)。
  • 通常 \(R\ne S\)。
  • 同一层的神经元不必用同一个传递函数:可以把两个网络并联成"复合层",它们共享输入、各自产出一部分输出。
  • 原书不把输入算作一层。所以"两层网络"指一个隐层加一个输出层。

1.4.2 多层网络

每一层都有自己的权值矩阵、偏置向量、净输入向量和输出向量,用上标区分层号。三层网络是

\[\mathbf{a}^1=\mathbf{f}^1(\mathbf{W}^1\mathbf{p}+\mathbf{b}^1),\quad \mathbf{a}^2=\mathbf{f}^2(\mathbf{W}^2\mathbf{a}^1+\mathbf{b}^2),\quad \mathbf{a}^3=\mathbf{f}^3(\mathbf{W}^3\mathbf{a}^2+\mathbf{b}^3),\]

合起来

\[\mathbf{a}^3=\mathbf{f}^3\Big(\mathbf{W}^3\,\mathbf{f}^2\big(\mathbf{W}^2\,\mathbf{f}^1(\mathbf{W}^1\mathbf{p}+\mathbf{b}^1)+\mathbf{b}^2\big)+\mathbf{b}^3\Big).\]

维数:\(\mathbf{W}^1\) 是 \(S^1\times R\),\(\mathbf{W}^2\) 是 \(S^2\times S^1\),\(\mathbf{W}^3\) 是 \(S^3\times S^2\)。第 2 层可以看成"输入数 \(R=S^1\)、神经元数 \(S=S^2\)"的单层网络——多层网络就是单层网络的串联。

白话解释:多层网络为什么必须有非线性传递函数?如果每层都用 purelin,\(\mathbf{a}^2=\mathbf{W}^2(\mathbf{W}^1\mathbf{p}+\mathbf{b}^1)+\mathbf{b}^2=(\mathbf{W}^2\mathbf{W}^1)\mathbf{p}+(\mathbf{W}^2\mathbf{b}^1+\mathbf{b}^2)\),合起来仍是"一个矩阵乘 \(\mathbf{p}\) 再加一个向量",和单层线性网络一模一样,叠多少层都只是一次线性回归。正是中间夹着的非线性 \(\mathbf{f}^1\) 让层数产生意义。这有点像用多个线性因子模型串联,结果依然是一个线性因子模型;要捕捉"动量在极端值反转"这类关系,必须引入非线性。

输出就是网络输出的那一层叫输出层(output layer),其余叫隐层(hidden layer)。上面的例子有一个输出层(第 3 层)和两个隐层。

多层网络比单层强得多。原书给出一个将在第 11 章证明的结论:第一层用 S 型函数、第二层用线性函数的两层网络,经过训练可以以任意精度逼近大多数函数;单层网络做不到。原书习题 E2.6 让我们手算一个小例子,体会这件事是怎么发生的(见本章量化实战代码的最后一段):两个 satlin 神经元各产生一个"斜坡",第二层把两个斜坡相减,就拼出一个"凸起"(bump)。很多凸起叠加起来,就能拼出任意形状的函数。

1.4.3 如何选择网络结构

原书给出三条规则:

  1. 网络输入数 = 问题的输入数;
  2. 输出层神经元数 = 问题的输出数;
  3. 输出层传递函数至少部分由输出规格决定。例如输出只取 \(-1\) 或 \(1\),就用对称硬限幅;输出在 0 到 1 之间连续变化,就用 logsig。

因此,单层网络的结构几乎完全由问题规格决定。多层网络则不然:隐层神经元数无法由外部问题直接确定,很少有问题能事先知道最优的隐层规模(第 11、13a 章再讨论)。实用网络大多只有两三层,四层以上少见(这是原书写作时的经验;深度网络是另一个话题)。

例(原书 P2.4) 单层网络,6 个输入、2 个输出,输出在 0 到 1 之间连续。答:需要 2 个神经元;权值矩阵 \(2\times6\);传递函数宜用 logsig;是否需要偏置,信息不足以判断。

偏置的作用。有偏置的网络多一个自由参数,能力更强。一个具体的理由:没有偏置时,输入 \(\mathbf{p}=\mathbf{0}\) 的净输入恒为 0,输出被锁死在 \(f(0)\),这往往不合需要。后面某些例子省略偏置,只是为了减少参数,好在二维平面上画收敛过程。

1.4.4 循环网络

前面的网络都是严格前馈(feedforward)的:信号从输入单向流到输出。要表达时间行为,需要两个新构件。

延迟块(delay):

\[a(t)=u(t-1),\tag{2.7}\]

时间取整数值。延迟块需要初始条件 \(a(0)\)。

积分器(integrator),用于第 18、19 章(原书第 18–21 章)的连续时间网络:

\[a(t)=\int_0^t u(\tau)\,d\tau+a(0).\tag{2.8}\]

循环网络(recurrent network)是带反馈的网络,部分输出连回输入。原书图 2.13 的离散时间循环网络是

\[\mathbf{a}(0)=\mathbf{p},\qquad \mathbf{a}(t+1)=\mathrm{satlins}\big(\mathbf{W}\mathbf{a}(t)+\mathbf{b}\big),\]

其中 \(\mathbf{W}\) 是 \(S\times S\) 方阵,输入 \(\mathbf{p}\) 只提供初始条件,此后网络自己演化。循环网络潜在能力强于前馈网络,能表现时间行为(第 03、14、18、19 章)。第 3 章的 Hopfield 网络就是这种结构;第 6 章(本册第 05 章)的特征值分析将回答"反复乘 \(\mathbf{W}\) 会收敛、发散还是振荡"。

金融直觉:延迟块 \(a(t)=u(t-1)\) 就是时间序列里的"滞后一期"算子,和 AR(1) 模型 \(x_t=\phi x_{t-1}+\varepsilon_t\) 里的 \(x_{t-1}\) 是一回事。循环网络 \(\mathbf{a}(t+1)=\mathrm{satlins}(\mathbf{W}\mathbf{a}(t)+\mathbf{b})\) 可以看成带"截断"的向量自回归(VAR):去掉 satlins,它就是 \(\mathbf{a}(t+1)=\mathbf{W}\mathbf{a}(t)+\mathbf{b}\)。你知道 AR(1) 在 \(|\phi|<1\) 时平稳、\(|\phi|>1\) 时发散;向量情形下起 \(\phi\) 作用的是 \(\mathbf{W}\) 的特征值,这正是第 05 章要讲的。


1.5 量化实战:把因子映射成交易信号的网络

1.5.1 结构由问题规格决定

把本章三条结构规则直接翻译到量化场景:

  • 输入数 = 因子数。用动量、反转、价值、规模、波动率 5 个因子,\(R=5\)。
  • 输出数 = 预测目标数。只预测一只股票下期是否跑赢,\(S^{\text{out}}=1\);同时预测 1 日、5 日、20 日三个期限的收益,\(S^{\text{out}}=3\)。
  • 输出层传递函数由目标类型决定:
    • 预测连续的超额收益 → purelin(这就是线性回归的网络形式);
    • 预测上涨与否、给出概率 → logsig,输出在 \((0,1)\),可以读作概率(第 11 章用交叉熵训练时这种解读才严格成立);
    • 看空/中性/看多三分类 → 三个输出神经元配 compet(或其光滑版 softmax)。
  • 隐层规模无法由问题决定,只能靠验证集实验和正则化来选——这正是量化中过拟合的高发区,第 13a、13b 章(泛化)专门讨论。

偏置的量化含义。因子通常先做截面标准化(均值 0、标准差 1)。一只各因子都恰好处于截面均值的"中性股票",输入就是 \(\mathbf{p}=\mathbf{0}\)。如果网络没有偏置,它对这只股票的输出被锁死在 \(f(0)\)(logsig 下是 0.5,purelin 下是 0),不管训练成什么样。如果市场整体有正的期望超额收益或预测目标本身不以 0 为中心,这就是系统性偏差。所以除非有明确理由,模型都应带偏置(回归里就是带截距)。

1.5.2 数据布局:原书"列是样本"与 pandas"行是样本"

原书把每个输入向量写成列向量,\(Q\) 个样本并排就是 \(R\times Q\) 的矩阵 \(\mathbf{P}\),一层的批量计算是 \(\mathbf{f}(\mathbf{W}\mathbf{P}+\mathbf{b})\),偏置按列广播。pandas 的因子表习惯是一行一只股票(\(Q\times R\)),所以从 DataFrame 取数时要转置一次。本册的所有代码都遵循原书约定,在注释里写清楚形状。

1.5.3 代码

下面用 numpy 实现表 2.1 的传递函数,核对原书 P2.2、P2.3 的数字,然后对 500 只模拟股票做一次两层网络的前向计算(权值随机,只演示结构与维数,不训练——训练是第 4 章以后的事),最后复现 E2.6 的"斜坡相减成凸起"。

import numpy as np
import pandas as pd

# ---------- 表 2.1 的传递函数(numpy 版) ----------
hardlim  = lambda n: (n >= 0).astype(float)
hardlims = lambda n: np.where(n >= 0, 1.0, -1.0)
purelin  = lambda n: n
satlin   = lambda n: np.clip(n, 0.0, 1.0)
satlins  = lambda n: np.clip(n, -1.0, 1.0)
logsig   = lambda n: 1.0 / (1.0 + np.exp(-n))
tansig   = np.tanh
poslin   = lambda n: np.maximum(n, 0.0)
def compet(n):                       # 对一整层(列向量/矩阵每列)取胜者
    a = np.zeros_like(n, dtype=float)
    a[np.argmax(n, axis=0), np.arange(n.shape[1])] = 1.0
    return a

# ---------- 核对原书 P2.2、P2.3 ----------
n = np.array(2.3 * 2.0 - 3.0)
print("P2.2  n=%.1f hardlim=%.0f purelin=%.1f logsig=%.4f"
      % (n, hardlim(n), purelin(n), logsig(n)))
W = np.array([[3.0, 2.0]]); p = np.array([[-5.0], [6.0]]); b = 1.2
n = W @ p + b
print("P2.3  n=%.1f hardlims=%.0f satlin=%.0f tansig=%.4f"
      % (n.item(), hardlims(n).item(), satlin(n).item(), tansig(n).item()))

# ---------- 量化场景:5 个因子 -> 上涨概率 的两层网络(前向计算) ----------
rng = np.random.default_rng(42)
R, S1, S2, Q = 5, 8, 1, 500          # 因子数、隐层神经元、输出数、股票数
factors = pd.DataFrame(rng.standard_normal((Q, R)),
                       columns=["mom", "rev", "val", "size", "vol"])
P = factors.to_numpy().T             # 原书约定:每一列是一个样本 -> R x Q

W1 = rng.normal(0, 0.5, (S1, R)); b1 = rng.normal(0, 0.1, (S1, 1))
W2 = rng.normal(0, 0.5, (S2, S1)); b2 = np.zeros((S2, 1))
A1 = tansig(W1 @ P + b1)             # S1 x Q,偏置按列广播
A2 = logsig(W2 @ A1 + b2)            # S2 x Q,(0,1) 之间,可读作"上涨概率"
print("shapes: W1", W1.shape, "W2", W2.shape, "A1", A1.shape, "A2", A2.shape)
print("prob range: [%.3f, %.3f]" % (A2.min(), A2.max()))

# 三分类(看空/中性/看多):输出层 3 个神经元 + compet
W3 = rng.normal(0, 0.5, (3, S1)); b3 = np.zeros((3, 1))
labels = compet(W3 @ A1 + b3)
print("class counts (short/flat/long):", labels.sum(axis=1).astype(int))

# ---------- 无偏置的后果:标准化后"中性"股票被强行映射到 0 ----------
zero_stock = np.zeros((R, 1))
print("no-bias net on zero input -> logsig(0) =",
      logsig(W2 @ tansig(W1 @ zero_stock)).item())

# ---------- E2.6:两层 satlin + purelin 网络是分段线性函数 ----------
p = np.linspace(-3, 3, 13).reshape(1, -1)
W1 = np.array([[2.0], [1.0]]); b1 = np.array([[2.0], [-1.0]])
W2 = np.array([[1.0, -1.0]]);  b2 = np.array([[0.0]])
a2 = purelin(W2 @ satlin(W1 @ p + b1) + b2)
print("E2.6 p :", p.ravel())
print("E2.6 a2:", a2.ravel())

运行输出:

P2.2  n=1.6 hardlim=1 purelin=1.6 logsig=0.8320
P2.3  n=-1.8 hardlims=-1 satlin=0 tansig=-0.9468
shapes: W1 (8, 5) W2 (1, 8) A1 (8, 500) A2 (1, 500)
prob range: [0.122, 0.885]
class counts (short/flat/long): [203 155 142]
no-bias net on zero input -> logsig(0) = 0.5
E2.6 p : [-3.  -2.5 -2.  -1.5 -1.  -0.5  0.   0.5  1.   1.5  2.   2.5  3. ]
E2.6 a2: [0.  0.  0.  0.  0.  1.  1.  1.  1.  0.5 0.  0.  0. ]

解读:

  • 前两行与原书 P2.2、P2.3 的数字完全一致。
  • 形状一行验证了维数规则:\(\mathbf{W}^1\) 是 \(S^1\times R=8\times5\),\(\mathbf{W}^2\) 是 \(S^2\times S^1=1\times8\),500 只股票被一次矩阵乘法处理完。
  • 无偏置网络对"中性股票"的输出恰好是 0.5,与权值无关——无论训练出什么权值,这只股票都被判为"五五开"。
  • E2.6 的输出:\(p<-1\) 时为 0,\(p\) 从 \(-1\) 到 \(-0.5\) 线性升到 1,在 \([-0.5,1]\) 上保持 1,\(p\) 从 1 到 2 线性降回 0。第一个神经元 \(\mathrm{satlin}(2p+2)\) 在 \(p\in[-1,-0.5]\) 上爬坡,第二个神经元 \(\mathrm{satlin}(p-1)\) 在 \(p\in[1,2]\) 上爬坡,第二层做减法得到一个梯形"凸起"。这就是"多层网络能逼近任意函数"的最小模型:换成 S 型函数,凸起就变光滑;多放几组神经元,就能在不同位置放不同高度的凸起。对因子研究来说,这意味着两层网络能自动学到"因子值在中间区间有效、两端失效"这类非单调关系,而线性模型做不到。

本章小结

神经网络由大量简单、高度互联的计算单元组成,功能由连接权决定,学习就是调整连接。历史上经历了 1940 年代起源、1950 年代末感知机与 ADALINE、1969 年后的低潮、1980 年代 Hopfield 网络与反向传播带来的复兴。本章最重要的是记号:一个神经元计算 \(a=f(\mathbf{W}\mathbf{p}+b)\),一层计算 \(\mathbf{a}=\mathbf{f}(\mathbf{W}\mathbf{p}+\mathbf{b})\),\(\mathbf{W}\) 是 \(S\times R\)、\(w_{i,j}\) 从第 \(j\) 个输入连到第 \(i\) 个神经元;多层网络用上标标层号,是单层网络的串联。单层网络的结构几乎完全由问题规格决定,多层网络的隐层规模则要靠经验与实验。循环网络通过延迟或积分器引入反馈,具有时间动态。

概念 公式 / 要点
单输入神经元 \(a=f(wp+b)\),\(n=wp+b\) 为净输入
多输入神经元 \(a=f(\mathbf{W}\mathbf{p}+b)\),\(\mathbf{W}\) 为 \(1\times R\)
一层 \(\mathbf{a}=\mathbf{f}(\mathbf{W}\mathbf{p}+\mathbf{b})\),\(\mathbf{W}\) 为 \(S\times R\),\(\mathbf{b},\mathbf{a}\) 为 \(S\times1\)
权值下标 \(w_{i,j}\):第 \(j\) 个来源 → 第 \(i\) 个目标神经元
多层 \(\mathbf{a}^{m+1}=\mathbf{f}^{m+1}(\mathbf{W}^{m+1}\mathbf{a}^m+\mathbf{b}^{m+1})\),\(\mathbf{W}^{m+1}\) 为 \(S^{m+1}\times S^m\)
常用传递函数 hardlim/hardlims(分类),purelin(线性),logsig/tansig(可微、多层),poslin(ReLU),compet(竞争)
结构规则 输入数 = 问题输入数;输出神经元数 = 问题输出数;输出层传递函数由输出规格决定
偏置 输入恒为 1 的权值;无偏置时 \(\mathbf{p}=\mathbf{0}\) 的输出锁死为 \(f(0)\)
延迟 / 积分器 \(a(t)=u(t-1)\);\(a(t)=\int_0^t u(\tau)d\tau+a(0)\)
离散循环网络 \(\mathbf{a}(0)=\mathbf{p}\),\(\mathbf{a}(t+1)=\mathrm{satlins}(\mathbf{W}\mathbf{a}(t)+\mathbf{b})\)

练习

基础

  1. 单输入神经元 \(w=1.3\),\(b=3.0\)。观察到输出分别为 1.6、1.0、0.9963、−1.0。对每个输出,判断它可能来自表 2.1 中的哪些传递函数,并求对应的输入 \(p\)。(原书 E2.1) 提示:先看值域排除。1.6 只可能来自 purelin 或 poslin,\(n=1.6\Rightarrow p=(1.6-3)/1.3\approx-1.077\)。−1.0 可能来自 hardlims(\(n<0\),即 \(p<-2.31\))、satlins(\(n\le-1\),即 \(p\le-3.08\))或 purelin(\(p=-3.08\));tansig 只能无限接近 −1 而取不到。0.9963 落在 \((0,1)\) 内,可能来自 logsig(\(n=\ln(0.9963/0.0037)\approx5.6\),\(p\approx2.0\))或 tansig(\(n=\operatorname{artanh}(0.9963)\approx3.15\)),也可能来自 purelin、satlin、satlins、poslin。
  2. 设计一个带偏置的单输入神经元,使 \(p<3\) 时输出 −1,\(p\ge3\) 时输出 +1。(原书 E2.2) 答案要点:用 hardlims;跳变点 \(-b/w=3\),即 \(b=-3w\) 且 \(w>0\)。
  3. \(\mathbf{W}=[3\ \ 2]\),\(\mathbf{p}=[-5\ \ 7]^T\),希望输出 0.5。(a) 偏置为零时哪种传递函数可行?(b) 线性传递函数需要多大偏置?(c) logsig 需要多大偏置?(d) 对称硬限幅能否做到?(原书 E2.3) 答案要点:\(\mathbf{W}\mathbf{p}=-1\)。(a) 零偏置时 \(n=-1\),表中没有函数在 \(-1\) 处取 0.5。(b) \(b=1.5\)。(c) \(\mathrm{logsig}(0)=0.5\),故 \(b=1\)。(d) 不能,hardlims 只输出 ±1。
  4. 两层网络,4 个输入、6 个输出,输出在 0 到 1 之间连续。各层神经元数、权值矩阵维数、可用传递函数、是否需要偏置,哪些能确定、哪些不能?(原书 E2.4) 答案要点:输出层 6 个神经元、用 logsig;\(\mathbf{W}^1\) 为 \(S^1\times4\),\(\mathbf{W}^2\) 为 \(6\times S^1\);\(S^1\) 与隐层传递函数、偏置是否需要都无法由题目确定。
  5. 写出三层网络 \(R=10\),\(S^1=20\),\(S^2=5\),\(S^3=1\) 时每个参数矩阵、偏置向量的形状,并数出可训练参数总数。 答案:\(20\times10+20+5\times20+5+1\times5+1=331\)。

进阶

  1. 在 \(-3<p<3\) 上手算并画出 E2.6 网络的 \(n^1_1,a^1_1,n^1_2,a^1_2,n^2_1,a^2_1\)。再把第二层权值改为 \([1\ \ 1]\),函数形状变成什么?(原书 E2.6) 提示:改为相加后,得到一个从 0 升到 1、保持、再升到 2 的"两级台阶"。体会:第二层权值决定各"基函数"如何组合。
  2. 证明 \(\tanh(n)=2\,\mathrm{logsig}(2n)-1\),并说明:把隐层的 logsig 全部换成 tansig,只要相应调整权值和偏置,网络能表示的函数集合不变。 提示:把 \(2\,\mathrm{logsig}(2n)-1\) 中的系数 2、−1 分别吸收进本层权值和下一层的权值、偏置。
  3. 原书声称"第一层 S 型、第二层线性的两层网络可逼近大多数函数,单层网络做不到"。用一个具体例子说明单层 purelin 网络做不到什么(例如对 \(p\in[-1,1]\) 逼近 \(p^2\))。 提示:单层 purelin 网络输出是 \(p\) 的仿射函数,无法表示任何非单调关系。
  4. 量化思考:你要预测下一日的已实现波动率(取值为正、连续)。输出层应该用哪种传递函数?如果改为预测"波动率是否上升"呢? 答案要点:正值连续目标可用 poslin,或用 purelin 预测对数波动率再取指数;二分类用 logsig。

原书推荐习题:E2.3(偏置与传递函数值域的配合)、E2.6(两层分段线性网络,理解函数逼近的关键)、E2.4 与 P2.4(由问题规格确定结构)。第 1 章无习题。


原书对照

本章内容 原书章节 PDF 页码
1.1 背景与历史 第 1 章 Introduction:1.1 历史、1.2 应用、1.3 生物学启发、延伸阅读 p.23–35
1.2 记号 第 2 章 Notation p.37
1.3 神经元模型与传递函数 第 2 章 Neuron Model,表 2.1 p.37–43
1.4 网络结构、循环网络 第 2 章 Network Architectures p.44–50
结果汇总 第 2 章 Summary of Results p.51–54
已解习题 P2.1–P2.4 第 2 章 Solved Problems p.55–56
习题 E2.1–E2.6 第 2 章 Exercises p.58–60

原书前言(PDF p.18–22)给出了章节依赖图:第 1–6 章是全书基础;第 7、15–19 章是联想与竞争网络;第 8–14、17 章是性能学习;第 20、21 章是循环联想记忆;第 22–27 章是实际训练技巧与案例。配套的 MATLAB 演示程序(nnd2n1 单输入神经元、nnd2n2 两输入神经元)可在原书网站下载,本册用 numpy 代码代替。