第 01 章 引言与神经元模型
本章合并原书第 1 章(引言)与第 2 章(神经元模型与网络结构)。第 1 章是历史与背景,压缩成一节;第 2 章确立全书记号,是后面每一章都要用的"语言",需要完全掌握。
学习目标
读完本章,你应当能够:
- 用一两句话说清神经网络的发展脉络:McCulloch–Pitts 神经元、感知机与 ADALINE、1969 年后的低潮、Hopfield 网络与反向传播带来的复兴,并知道每个节点在本书哪一章展开。
- 写出单输入、多输入神经元的数学模型 \(a=f(\mathbf{W}\mathbf{p}+b)\),说清权值、偏置、净输入、传递函数各自的作用。
- 熟记表 2.1 中九种传递函数的定义、值域和典型用途,能根据输出要求选择输出层传递函数。
- 写出单层与多层网络的矩阵形式,正确标注每个矩阵和向量的维数,理解权值下标 \(w_{i,j}\)"目标在前、来源在后"的约定。
- 根据问题规格确定单层网络的结构,知道多层网络中哪些部分无法由问题直接决定。
- 理解延迟、积分器与循环网络的含义,知道它们为什么能表达时间行为。
读前导读
这一章在解决什么问题
结论先说:一个人工神经元,就是一次"线性回归 + 一个非线性开关"。你在 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)。神经元的排列方式和突触的强度共同决定了网络的功能。一部分结构是天生的,其余通过学习形成:幼年时主要是建立新连接、淘汰旧连接;成年后主要是改变突触的强弱。原书举了几个例子:幼猫在关键期被剥夺单眼视觉,那只眼睛以后永远无法正常视物;伦敦出租车司机的海马体明显偏大,因为他们要花约两年记忆大量路线。
人工神经网络与生物网络只有两点关键相似:
- 基本单元都是高度互联的简单计算单元;
- 单元之间的连接决定网络的功能。
所以本书的核心任务可以一句话概括:为特定问题找到合适的连接(权值)。这句话请记住,后面所有的"学习规则""训练算法"都是在回答"怎样找到合适的权值"。
生物神经元很慢(约 \(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):
净输入经过传递函数(transfer function,也常叫激活函数 activation function)\(f\) 得到输出:
与生物神经元对照:\(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):
用来把输入分成两类,第 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):
把整条实轴压缩到 \((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}\),加上偏置:
写成矩阵形式(单个神经元时 \(\mathbf{W}\) 只有一行):
权值下标约定:\(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\)。净输入
用对称硬限幅得 \(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{b}\)(\(S\times1\))、传递函数和输出向量 \(\mathbf{a}\)(\(S\times1\)):
要点:
- 行下标 = 目标神经元,列下标 = 输入来源。\(\mathbf{W}\) 的第 \(i\) 行就是第 \(i\) 个神经元的全部输入权值。第 4 章会把这一行记作列向量 \({}_i\mathbf{w}\),它在几何上有清楚的含义(决策边界的法向量)。
- 通常 \(R\ne S\)。
- 同一层的神经元不必用同一个传递函数:可以把两个网络并联成"复合层",它们共享输入、各自产出一部分输出。
- 原书不把输入算作一层。所以"两层网络"指一个隐层加一个输出层。
1.4.2 多层网络
每一层都有自己的权值矩阵、偏置向量、净输入向量和输出向量,用上标区分层号。三层网络是
合起来
维数:\(\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\) 或 \(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(0)\)。
积分器(integrator),用于第 18、19 章(原书第 18–21 章)的连续时间网络:
循环网络(recurrent network)是带反馈的网络,部分输出连回输入。原书图 2.13 的离散时间循环网络是
其中 \(\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})\) |
练习
基础
- 单输入神经元 \(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。
- 设计一个带偏置的单输入神经元,使 \(p<3\) 时输出 −1,\(p\ge3\) 时输出 +1。(原书 E2.2) 答案要点:用 hardlims;跳变点 \(-b/w=3\),即 \(b=-3w\) 且 \(w>0\)。
- \(\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 个输入、6 个输出,输出在 0 到 1 之间连续。各层神经元数、权值矩阵维数、可用传递函数、是否需要偏置,哪些能确定、哪些不能?(原书 E2.4) 答案要点:输出层 6 个神经元、用 logsig;\(\mathbf{W}^1\) 为 \(S^1\times4\),\(\mathbf{W}^2\) 为 \(6\times S^1\);\(S^1\) 与隐层传递函数、偏置是否需要都无法由题目确定。
- 写出三层网络 \(R=10\),\(S^1=20\),\(S^2=5\),\(S^3=1\) 时每个参数矩阵、偏置向量的形状,并数出可训练参数总数。 答案:\(20\times10+20+5\times20+5+1\times5+1=331\)。
进阶
- 在 \(-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 的"两级台阶"。体会:第二层权值决定各"基函数"如何组合。
- 证明 \(\tanh(n)=2\,\mathrm{logsig}(2n)-1\),并说明:把隐层的 logsig 全部换成 tansig,只要相应调整权值和偏置,网络能表示的函数集合不变。 提示:把 \(2\,\mathrm{logsig}(2n)-1\) 中的系数 2、−1 分别吸收进本层权值和下一层的权值、偏置。
- 原书声称"第一层 S 型、第二层线性的两层网络可逼近大多数函数,单层网络做不到"。用一个具体例子说明单层 purelin 网络做不到什么(例如对 \(p\in[-1,1]\) 逼近 \(p^2\))。 提示:单层 purelin 网络输出是 \(p\) 的仿射函数,无法表示任何非单调关系。
- 量化思考:你要预测下一日的已实现波动率(取值为正、连续)。输出层应该用哪种传递函数?如果改为预测"波动率是否上升"呢? 答案要点:正值连续目标可用 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 代码代替。