第 15 章 联想学习与竞争网络
本章合并原书第 15 章(Associative Learning)与第 16 章(Competitive Networks)。两章讲的是一条线:第 15 章给出几条简单的无监督局部学习规则(Hebb、instar、Kohonen、outstar),第 16 章用这些规则搭出能自行学习分类的网络(竞争层、自组织特征图 SOFM、学习向量量化 LVQ)。它们与量化交易的直接关系较弱,本章做压缩讲解:保留核心规则、代表性例题和数字,略去生物学和心理学背景的细节。真正在量化中有用的是两点:Kohonen 规则就是指数移动平均式的原型更新;竞争学习和 SOFM 是在线聚类工具,可用于市场状态识别。
学习目标
读完本章,你应当能够:
- 写出无监督 Hebb 规则、带衰减的 Hebb 规则、instar 规则、Kohonen 规则和 outstar 规则,说清它们各自"何时学习、向哪里移动"。
- 用 \(\|\mathbf{w}\|\|\mathbf{p}\|\cos\theta\ge-b\) 解释 instar 的识别条件,以及偏置如何控制识别的严格程度。
- 说明竞争层 \(\mathbf{a}=\mathrm{compet}(\mathbf{W}\mathbf{p})\) 与 Kohonen 规则如何组成在线聚类器,并列出竞争学习的四个问题(学习率权衡、近簇不稳定、死神经元、只能凸区域)。
- 说明 SOFM 如何通过邻域更新学到输入空间的拓扑,LVQ 如何用"子类合并"构造非凸的类。
- 用竞争学习和一维 SOFM 对模拟的市场状态做在线聚类,并知道良心机制与无前视标准化的做法。
读前导读
本章是选读章。 它与量化的关系较弱,第一次读本册时可以只看本导读和 15.5 节,等需要做聚类或市场状态识别时再回来细读。
这一章在解决什么问题。 前面各章的网络都是"有老师"的:给出目标输出,按误差调权值。本章换成"没有老师"的学习:网络只看输入,自己把相似的输入归到一起。你可以把它理解成一种在线的、逐笔更新的聚类方法。对量化读者,最值得带走的只有两句话:第一,Kohonen 规则 \({}_i\mathbf{w}\leftarrow(1-\alpha){}_i\mathbf{w}+\alpha\mathbf{p}\) 就是你熟悉的 EWMA,只是被平滑的对象从一个价格换成了一个"原型向量";第二,竞争层就是在线 k-means,SOFM 在此基础上让"相邻状态"也排成有序的一串,便于观察市场在状态之间怎样迁移。
需要先想起来的数学。
- 向量内积与夹角:\(\mathbf{w}^T\mathbf{p}=\sum_j w_jp_j=\|\mathbf{w}\|\|\mathbf{p}\|\cos\theta\)。\(\|\cdot\|\) 是向量长度(欧氏范数)。长度固定时,内积越大说明两个向量方向越接近,这就是"余弦相似度"。例:\([1,0]\) 与 \([0.6,0.8]\) 内积 0.6,夹角约 53°。见 第 00 册第 06 章 线性代数速成。
- 矩阵乘向量 = 一组内积:\(\mathbf{W}\mathbf{p}\) 的第 \(i\) 个分量就是 \(\mathbf{W}\) 第 \(i\) 行与 \(\mathbf{p}\) 的内积。所以"权值的每一行是一个原型"意味着 \(\mathbf{W}\mathbf{p}\) 一次算出输入与所有原型的相似度。外积 \(\mathbf{a}\mathbf{p}^T\) 则是一个矩阵,第 \((i,j)\) 元是 \(a_ip_j\)。
- 几何级数与稳态:\(w\leftarrow(1-\gamma)w+\alpha\) 反复迭代会收敛到满足 \(w=(1-\gamma)w+\alpha\) 的点,即 \(w=\alpha/\gamma\)。这和年金现值里的几何级数求和是同一件事。见 第 00 册第 04 章 级数与收敛。
怎么读这一章。 15.1 节的四条规则只需记住表格里的"何时更新、向哪里移动";15.2.2–15.2.3(竞争学习及其四个问题)是核心;15.3 SOFM 和 15.4 LVQ 第一次可以只看结论;15.5 节的实战代码值得完整读一遍,特别是"标准化只用训练段统计量"和"死神经元"两点。
15.1 联想学习:四条局部规则
15.1.1 联想与简单联想网络
联想(association)是输入与输出之间的任意联系:给出模式 A(刺激,stimulus)时系统给出模式 B(响应,response)。心理学上的经典例子是 Pavlov 的狗:每次喂食时摇铃,狗最终听到铃声就分泌唾液。Hebb(1949)提出了细胞层面的机制:两个细胞反复同时活跃,它们之间的连接就会加强。
最简单的联想器是单输入硬限幅神经元 \(a=\mathrm{hardlim}(wp+b)\),\(p,a\in\{0,1\}\)。取 \(b=-0.5\),只有 \(w>0.5\) 时刺激才引起响应。为了演示学习,原书使用两类输入:
- 无条件刺激 \(p^0\)(类比食物):天生会引起响应,权值 \(w^0\) 固定;
- 条件刺激 \(p\)(类比铃声):权值 \(w\) 靠学习改变。
"香蕉联想器":\(a=\mathrm{hardlim}(w^0p^0+wp-0.5)\),\(p^0\) 为是否看到香蕉形状,\(p\) 为是否闻到香蕉气味,初值 \(w^0=1\)、\(w=0\)。开始时网络只凭视觉识别香蕉。
15.1.2 无监督 Hebb 规则
同时出现就加强:
它是局部学习规则(local learning rule):只用被更新权值两端可得的信号,不像反向传播那样需要从输出层传回敏感度。本章所有规则都是局部的。
香蕉例子(\(\alpha=1\),视觉只在偶数步工作,嗅觉始终可靠):
- \(q=1\):只有气味,\(a=\mathrm{hardlim}(0+0-0.5)=0\),\(w\) 不变;
- \(q=2\):看到形状,\(a=1\),同时闻到气味,\(w(2)=0+1\cdot1=1\);
- \(q=3\):只有气味,但 \(a=\mathrm{hardlim}(0+1-0.5)=1\),网络已学会凭气味识别,\(w(3)=2\)。
缺陷有二:继续训练 \(w\) 会无界增长;没有让权值减小的机制,输入有噪声时所有权值都会慢慢变大,最终网络对任何刺激都响应。
15.1.3 带衰减的 Hebb 规则
令 \(a_i=p_j=1\) 并令新旧权值相等,得权值上限
推导拆解:式 (15.19) 的来历。设 \(a_i=p_j=1\) 一直成立,更新式变成 \(w(q)=(1-\gamma)w(q-1)+\alpha\)。"权值不再变化"意味着 \(w(q)=w(q-1)=w^{\max}\),代入得 \(w^{\max}=(1-\gamma)w^{\max}+\alpha\),移项 \(\gamma w^{\max}=\alpha\)。也可以把迭代展开:从 \(w(0)=0\) 出发,\(w(q)=\alpha\big[1+(1-\gamma)+\dots+(1-\gamma)^{q-1}\big]\),这是公比 \(1-\gamma\) 的几何级数,\(q\to\infty\) 时和为 \(\alpha/\gamma\)。交替情形同理:两步合并后公比变成 \((1-\gamma)^2\),所以上限是 \(\alpha/\big(1-(1-\gamma)^2\big)=\alpha/\big(\gamma(2-\gamma)\big)\)。
香蕉例子取 \(\gamma=0.1\):\(w(3)=1+1-0.1=1.9\),之后指数式趋近 \(w^{\max}=10\)。小的随机增量会很快衰减掉,学到的联想不会是噪声的产物。代价是:若刺激长期不出现(\(a_i=0\)),\(w_{ij}(q)=0.9\,w_{ij}(q-1)\),每步丢掉 10%,旧联想终将遗忘。
原书例题 P15.1 进一步计算:若 \(a_ip_j\) 在 0 和 1 之间交替,两步合并得 \(w(q+2)=(1-\gamma)^2w(q)+\alpha\),稳态上限为 \(w^{\max}=\alpha/\big(\gamma(2-\gamma)\big)\)。
量化读者会认出:\((1-\gamma)\) 就是 EWMA 的衰减因子,\(\alpha/\gamma\) 是持续输入 1 时 EMA 的稳态幅度。
15.1.4 instar:识别一个模式
instar 是向量输入、标量输出的神经元:
长度固定时,内积在两个向量同向时最大。取 \(b=-\|{}_1\mathbf{w}\|\|\mathbf{p}\|\),只有 \(\mathbf{p}\) 与 \({}_1\mathbf{w}\) 完全同向时才激活;把 \(b\) 调大,能激活的模式变多,判别力变弱。这个分析假设所有输入范数相同,所以本章网络普遍要求输入归一化。
原书例题 P15.4:\({}_1\mathbf{w}=[1;-1;-1]\),\(b=-2\),输入范数 \(\sqrt3\),激活条件为 \(3\cos\theta\ge2\),即 \(\theta\le48.19^\circ\)。这就是余弦相似度大于 \(2/3\)。
15.1.5 instar 规则与 Kohonen 规则
带衰减 Hebb 规则的问题是不强化就遗忘。改为只在神经元激活时才衰减,并令衰减率等于学习率,得到 instar 规则:
激活时 \({}_i\mathbf{w}(q)=(1-\alpha)\,{}_i\mathbf{w}(q-1)+\alpha\,\mathbf{p}(q)\):权值沿连线向输入移动,比例为 \(\alpha\)。不激活时权值不变,不会遗忘。若输入归一化,学会后的权值也是归一化的。
"橙子识别器"(原书例题):\(a=\mathrm{hardlim}(3p^0+\mathbf{W}\mathbf{p}-2)\),\(\mathbf{p}=[\text{形状};\text{纹理};\text{重量}]\) 取 \(\pm1\),橙子为 \([1;-1;-1]\),\(\mathbf{W}(0)=\mathbf{0}\)。\(\alpha=1\) 时第 2 步(看到橙子)权值一次拷贝成 \([1,-1,-1]\),第 3 步只凭测量就能识别。\(\alpha=0.4\) 时(P15.2):第 2、4、6 步权值依次为 \(0.4\)、\(0.64\)、\(0.784\) 乘以 \([1,-1,-1]\),到第 7 步 \(3\times0.784=2.352\ge2\),才能只凭测量识别。学习率低,需要更多次配对。
Kohonen 规则把"按输出 \(a_i\) 学习"换成"属于某个集合 \(X(q)\) 就学习":
当 \(X(q)\) 是激活神经元的集合时,它与 instar 规则等价;好处是 \(X(q)\) 可以另作定义,比如 SOFM 中"获胜者的邻域"。
15.1.6 outstar:回忆一个模式
outstar 是标量输入、向量输出:\(\mathbf{a}=\mathrm{satlins}(\mathbf{W}p)\)。让权值矩阵的唯一一列等于 \(\mathbf{a}^*\),输入 1 时就回忆出 \(\mathbf{a}^*\)。对比:识别网络把目标存在权值的行,回忆网络存在列。
outstar 规则让衰减正比于输入而不是输出:
只要 \(p_j\neq0\),第 \(j\) 列就向当前输出移动。"菠萝回忆器":测量 \(\mathbf{p}^0\) 经单位阵直接送到输出,\(p\) 表示是否看到菠萝;测量只在偶数步可用。第 2 步 \(\mathbf{w}_1\) 学成菠萝测量 \([-1;-1;1]\);第 3 步测量失效,看到菠萝就回忆出 \([-1;-1;1]\)。第 19 章的 ART 网络同时使用 instar 和 outstar。
15.2 竞争层与竞争学习
15.2.1 从 Hamming 网络到竞争层
第 3 章的 Hamming 网络两层:第 1 层是一层 instar,\(\mathbf{W}^1\) 的每一行是一个原型,偏置都等于输入维数 \(R\),输出 \(\mathbf{p}_i^T\mathbf{p}+R\) 衡量输入与各原型的接近程度;第 2 层用侧抑制(lateral inhibition)做竞争:
每次迭代各神经元按其他神经元输出之和成比例下降,初值最大的下降最慢,最后只剩它为正,即胜者全得(winner-take-all)。为简化,定义直接给出这个结果的传递函数:
若向量都归一化为长度 \(L\),\(n_i=L^2\cos\theta_i\),获胜者就是方向最接近输入的原型。
15.2.2 竞争学习
不知道原型时,用 instar 规则学习。竞争层中只有获胜者 \(a_{i^*}\neq0\),所以 instar 规则退化为只更新获胜者的 Kohonen 规则:
这就是在线 k-means:每个原型是它"赢得"的那些输入的指数加权平均。
金融直觉:把每个原型想成一位"板块分析师",各自盯着一类行情。每来一天数据,先问"今天最像谁负责的那类?"(竞争,选出 \(i^*\)),然后只有这位分析师用今天的数据更新自己的"典型画像",做法是 EWMA:旧画像占 \(1-\alpha\),今天占 \(\alpha\)。\(\alpha\) 越大,画像追新越快,但也越容易被单日噪声带偏,这就是 15.2.3 第 1 条的学习率权衡。批量 k-means 每轮用全部样本重算簇均值;在线版本每次只看一个样本,因此能跟随分布漂移,代价是结果依赖样本顺序。
原书例子:六个归一化二维向量分成三簇,三个神经元初值 \({}_1\mathbf{w}=[0.7071;-0.7071]\)、\({}_2\mathbf{w}=[0.7071;0.7071]\)、\({}_3\mathbf{w}=[-1;0]\)。输入 \(\mathbf{p}_2=[0.1961;0.9806]\) 时 \(\mathbf{W}\mathbf{p}_2=[-0.5547;0.8321;-0.1961]\),神经元 2 获胜;\(\alpha=0.5\) 更新为 \({}_2\mathbf{w}=[0.4516;0.8438]\)。反复呈现后,三个权值各自指向一个簇。
15.2.3 竞争学习的四个问题
- 学习率权衡:\(\alpha\) 小则慢但稳,\(\alpha\) 大则快但在簇内来回振荡。可以让学习率先大后小,但如果网络需要持续适应输入分布的变化,退火就不行了。
- 近簇不稳定:两簇靠得近时,一个原型可能"侵入"另一个原型的领地,打乱已有分类。
- 死神经元(dead neuron):初始权值离所有输入太远,永远赢不了、永远不学习。解决办法是良心机制(conscience,原书 E16.4):给净输入加偏置,赢家的偏置每赢一次减 0.2,其余神经元的偏置每步乘 0.9 向零恢复,让常胜者越来越难赢。
- 类别数固定且每类是凸区域:类数等于神经元数;每个原型负责的区域是 Voronoi 单元,无法表示非凸或不连通的类。
原书例题 P16.2 演示了死神经元:输入 \(\mathbf{p}_1=[-1;0]\)、\(\mathbf{p}_2=[0;1]\)、\(\mathbf{p}_3=[1/\sqrt2;1/\sqrt2]\),初值 \({}_1\mathbf{w}=[0;-1]\)、\({}_2\mathbf{w}=[-2/\sqrt5;1/\sqrt5]\)、\({}_3\mathbf{w}=[-1/\sqrt5;2/\sqrt5]\),\(\alpha=0.5\),按 \(\mathbf{p}_1,\mathbf{p}_2,\mathbf{p}_3\) 呈现两轮。结果 \({}_2\mathbf{w}=[-0.974;0.112]\) 几乎学会 \(\mathbf{p}_1\),\({}_3\mathbf{w}=[0.414;0.810]\) 落在 \(\mathbf{p}_2\)、\(\mathbf{p}_3\) 之间,\({}_1\mathbf{w}\) 从未更新。(精读笔记中 \({}_2\mathbf{w}\) 第二个分量记为 0.118,按 \(0.5\times0.2236=0.1118\) 应为 0.112。)
15.2.4 未归一化的输入
内积型竞争层要求输入归一化。原书 P16.7 给出三种处理:
- 直接归一化,但会丢掉幅度信息;
- 改用负距离 \(n_i=-\|{}_i\mathbf{w}-\mathbf{p}\|\) 作为净输入(LVQ 的做法),保留幅度;输入归一化时它与内积版的结果相同(E16.8);
- 先给每个输入追加常数 1 再归一化,追加分量等于扩展向量长度的倒数,间接保留幅度。例如 \([1;1]\to[1;1;1]/\sqrt3\),\([0;0]\to[0;0;1]\)。
这个取舍在量化里很常见:按波动率标准化特征会丢掉波动水平本身的信息,而波动水平往往就是区分市场状态的关键。
15.3 自组织特征图(SOFM)
生物神经元排成二维层,侧向连接呈墨西哥帽(Mexican hat)形状:近处兴奋,远处抑制;竞争的结果不是单个赢家,而是以最活跃神经元为中心的一团"活动泡"。Kohonen 用一个简化来模拟:先按竞争层的方法找出获胜者 \(i^*\),再用 Kohonen 规则更新获胜者邻域内的所有神经元:
在 \(5\times5\) 网格(编号 1–25)中,\(N_{13}(1)=\{8,12,13,14,18\}\),\(N_{13}(2)\) 含 13 个神经元。多次训练后,拓扑上相邻的神经元学到相似的原型,整张网在输入空间中铺开,而且按输入密度大致均匀地划分区域。
可能的失败是扭结(twist):网的两部分分别拟合了输入空间的不同区域,中间扭转,两端已稳定后几乎无法消除。改进办法:
- 邻域半径从大逐渐缩到只含获胜者,加快自组织,并使扭结极少出现;
- 学习率随时间递减,从接近 1 渐近到 0;
- 获胜者用比邻居更大的学习率;
- 用距离代替内积,免去归一化。
原书例题 P16.4:一维 9 个神经元,输入 \(\mathbf{p}=[0.67;0.07;0.74]\),神经元 2 获胜,半径 1 的邻域含 1、3,\(\alpha=0.1\) 时三者一起向输入移动。原书第 26 章(本册第 25 章后半)有批量版 SOFM 的聚类案例。
15.4 学习向量量化(LVQ)
LVQ 把竞争层放进有监督框架。第一层是用负距离的竞争层:
第一层获胜者代表一个子类(subclass);第二层是固定的线性层,\(w^2_{ki}=1\) 表示子类 \(i\) 属于类 \(k\),每列只有一个 1。多个凸的子类区域合并成一类,于是能构造非凸、甚至不连通的类区域。
学习时 \(\mathbf{W}^2\) 事先定好不再改变,只训练 \(\mathbf{W}^1\):
分类正确取"\(+\)"(获胜者靠近输入),分类错误取"\(-\)"(获胜者远离输入)。
XOR 例子:类 1 为 \([-1;-1]\)、\([1;1]\),类 2 为 \([1;-1]\)、\([-1;1]\),每类两个子类,\(\mathbf{W}^2=\begin{bmatrix}1&1&0&0\\0&0&1&1\end{bmatrix}\)。初值 \({}_1\mathbf{w}^1=[-0.543;0.840]\)、\({}_2\mathbf{w}^1=[-0.969;-0.249]\)、\({}_3\mathbf{w}^1=[0.997;0.094]\)、\({}_4\mathbf{w}^1=[0.456;0.954]\)。呈现 \(\mathbf{p}_3=[1;-1]\):\(\mathbf{n}^1=[-2.40;-2.11;-1.09;-2.03]\),第 3 个子类获胜,\(\mathbf{a}^2=[0;1]\),类 2,正确;\(\alpha=0.5\) 时 \({}_3\mathbf{w}^1=[0.998;-0.453]\)。收敛后四个原型分别靠近四个点,得到单个竞争层或感知机做不出的 XOR 区域。
LVQ2:初始布局不利时,一个原型可能要穿过别的类的区域才能到达自己的区域,途中被排斥而过不去。LVQ2 的修正是:分类错误时,除了把获胜者推远,还把离输入最近且属于正确类的原型拉近。
15.5 量化实战:用竞争学习和 SOFM 识别市场状态
场景。 我们希望把每个交易日归入少数几个"市场状态"(regime),例如平稳上涨、震荡、高波动下跌,用于切换策略参数或风险预算。竞争层就是在线 k-means,适合这种无监督、需要持续更新的任务;SOFM 还给出状态之间的"相邻关系",便于观察状态如何过渡。
要点。
- 特征只用过去数据(20 日滚动均值、波动率、最大回撤),标准化用的均值和标准差只取自训练段,避免前视偏差。
- 用负距离作净输入,不必把特征向量归一化成单位长度,保留波动水平等幅度信息。
- 故意把一半神经元放在远离数据的位置,观察死神经元和良心机制的效果。
- 模拟数据有真实状态标签,用"训练段多数表决给原型贴标签、测试段按最近原型预测"来衡量聚类是否抓住了状态。真实市场中没有标签,只能看原型的经济含义和稳定性。
import numpy as np
import pandas as pd
rng = np.random.default_rng(7)
# 1) 模拟三状态市场:0=平稳上涨,1=震荡,2=高波动下跌(马尔可夫切换)
mu = np.array([0.0008, 0.0, -0.0015])
vol = np.array([0.008, 0.012, 0.028])
P = np.array([[0.985, 0.010, 0.005],
[0.010, 0.980, 0.010],
[0.010, 0.020, 0.970]])
T = 5000
state = np.empty(T, dtype=int); state[0] = 0
for t in range(1, T):
state[t] = rng.choice(3, p=P[state[t - 1]])
ret = mu[state] + vol[state] * rng.standard_normal(T)
# 2) 特征:20 日均值收益、20 日波动率、20 日最大回撤(只用过去数据)
s = pd.Series(ret)
px = np.exp(s.cumsum())
feat = pd.DataFrame({
"mean20": s.rolling(20).mean() * 252,
"vol20": s.rolling(20).std() * np.sqrt(252),
"mdd20": px / px.rolling(20).max() - 1,
}).dropna()
lab = state[feat.index]
split = 3000
mu_f, sd_f = feat.iloc[:split].mean(), feat.iloc[:split].std() # 只用训练段统计量标准化
X = ((feat - mu_f) / sd_f).to_numpy()
Xtr, Xte, ytr, yte = X[:split], X[split:], lab[:split], lab[split:]
# 3) 竞争层(负距离净输入,式 16.25)+ Kohonen 规则,可选"良心"偏置
def train_competitive(X, S, epochs=5, conscience=False, seed=0):
r = np.random.default_rng(seed)
W = X[r.choice(len(X), S, replace=False)].copy()
W[S // 2:] += np.array([0.0, -2.0, 0.0]) # 一半神经元故意放到远离数据的位置
b = np.zeros(S); wins = np.zeros(S, dtype=int)
for ep in range(epochs):
lr = 0.1 * (1 - ep / epochs) + 0.01
for q in r.permutation(len(X)):
n = -np.linalg.norm(W - X[q], axis=1) + (b if conscience else 0)
i = np.argmax(n); wins[i] += 1
W[i] += lr * (X[q] - W[i]) # 只有获胜者向输入移动
if conscience: # E16.4 的良心机制
bi = b[i]; b *= 0.9; b[i] = bi - 0.2 # 输家偏置衰减,赢家偏置减 0.2
return W, wins
def assign(W, X):
return np.argmin(((X[:, None, :] - W[None]) ** 2).sum(-1), axis=1)
def purity(W, Xtr, ytr, Xte, yte):
ctr = assign(W, Xtr)
# 每个原型按训练段多数表决标上状态;测试段按最近原型预测
m = {c: np.bincount(ytr[ctr == c], minlength=3).argmax() for c in np.unique(ctr)}
cte = assign(W, Xte)
pred = np.array([m.get(c, -1) for c in cte])
return (pred == yte).mean()
for cons in (False, True):
W, wins = train_competitive(Xtr, S=6, conscience=cons)
print(f"良心机制={cons}: 各神经元获胜次数 {wins}, 样本外状态识别准确率 {purity(W, Xtr, ytr, Xte, yte):.3f}")
# 4) 一维 SOFM:8 个节点排成一条链,邻域半径从 2 递减到 0
def train_sofm(X, S=8, epochs=10, seed=0):
r = np.random.default_rng(seed)
W = X[r.choice(len(X), S, replace=False)].copy()
for ep in range(epochs):
d = int(round(2 * (1 - ep / (epochs - 1)))) # 邻域 2 -> 0
lr = 0.2 * (1 - ep / epochs) + 0.01
for q in r.permutation(len(X)):
i = np.argmin(np.linalg.norm(W - X[q], axis=1))
nb = np.arange(max(0, i - d), min(S, i + d + 1)) # N_i*(d)
W[nb] += lr * (X[q] - W[nb])
return W
Ws = train_sofm(Xtr)
proto = pd.DataFrame(Ws * sd_f.to_numpy() + mu_f.to_numpy(), columns=feat.columns).round(3)
proto["主要状态"] = [np.bincount(ytr[assign(Ws, Xtr) == c], minlength=3).argmax()
if (assign(Ws, Xtr) == c).any() else -1 for c in range(8)]
print("SOFM 节点原型(按链上顺序,已还原到原始尺度):")
print(proto.to_string())
print(f"SOFM 样本外状态识别准确率 {purity(Ws, Xtr, ytr, Xte, yte):.3f}")
输出:
良心机制=False: 各神经元获胜次数 [ 1920 2508 10572 0 0 0], 样本外状态识别准确率 0.649
良心机制=True: 各神经元获胜次数 [1880 4004 2109 3156 0 3851], 样本外状态识别准确率 0.717
SOFM 节点原型(按链上顺序,已还原到原始尺度):
mean20 vol20 mdd20 主要状态
0 -1.055 0.220 -0.090 1
1 -0.312 0.146 -0.037 0
2 0.340 0.125 -0.009 0
3 0.385 0.231 -0.012 1
4 2.057 0.379 -0.011 2
5 0.080 0.417 -0.047 2
6 -1.198 0.414 -0.122 2
7 -2.429 0.448 -0.189 2
SOFM 样本外状态识别准确率 0.729
解读。
- 不加良心机制时,三个放在远处的神经元一次都没赢过,是死神经元;有效聚类数只有 3,其中一个原型独占了 1 万多次胜利。加入良心机制后,两个死神经元被"救活",样本外识别率从 0.649 升到 0.717。离得最远的那个仍然没救活:良心偏置的幅度有上限(常胜者约为 \(-0.2/(1-0.9)=-2\)),离数据太远的神经元还是赢不了。实务中更稳妥的做法是用数据点初始化原型,良心机制作为补充。
白话解释:上面"约为 \(-2\)"是个粗略量级。代码里赢家这一步不衰减、只减 0.2,输家每步乘 0.9。若一个神经元每步都赢,它的偏置会一路减下去;但它一旦被压低到输给附近的活跃神经元,就开始衰减回升。几个活跃神经元轮流获胜时,各自的偏置在零下不远处来回波动(例如 4 个神经元均匀轮换,量级约 \(-0.5\))。结论不变:良心偏置只能在"彼此都离数据不远"的神经元之间重新分配胜利,对远离数据好几个标准差的神经元帮不上忙。
- SOFM 的 8 个节点沿链有序:节点 1、2 是低波动上涨(状态 0),节点 4→7 是高波动区,并且从"高波动反弹"逐步过渡到"深度回撤"。相邻节点代表相似状态,这正是 SOFM 相对于普通竞争层多出的信息:可以把每天所在的节点画成时间序列,观察市场在相邻状态间如何迁移。
- 震荡状态(状态 1)与平稳上涨的波动率只差约 6 个百分点(年化),20 日窗口下难以区分,所以准确率不高。这提醒我们:聚类只看输入分布,特征本身分辨不出的状态,任何聚类算法都分不出来。
- 结果依赖初值和数据顺序(原书 P16.3 的留问)。用于回测时固定随机种子,多次重跑检查状态划分是否稳定;原型要在滚动窗口内重新训练,而不是用全样本训练一次后回头贴标签。
其他用法。
- 股票聚类:用收益序列或因子暴露向量做竞争学习/SOFM,得到行业分类之外的"数据驱动板块",用于分散化、配对交易候选筛选、风险分组。
- LVQ 作可解释分类器:每个原型就是一个"典型形态",可用于方向或信号类别分类。但在高噪声金融数据上,它通常不如正则化线性模型或树模型稳健,需要严格的样本外检验。
- Kohonen 规则 = 原型的 EMA:学习率就是对新行情的适应速度。原书"需要持续适应时退火学习率失效"的提醒在非平稳市场中很实际:要么保留一个下限学习率,要么定期用滚动窗口重训。
本章小结
联想学习的核心是"同时出现就加强"。无监督 Hebb 规则 \(\Delta\mathbf{W}=\alpha\mathbf{a}\mathbf{p}^T\) 会让权值无界增长,加衰减后有上限 \(\alpha/\gamma\) 但会遗忘;instar 规则只在激活时学习,权值向输入移动,学会后不再遗忘;Kohonen 规则把"激活"换成"属于某个集合";outstar 规则把权值的列向输出移动,用于回忆。把 instar 层与胜者全得的竞争结合,就得到能在线学习原型的竞争层,它本质上是在线 k-means,存在学习率权衡、近簇不稳定、死神经元和只能凸区域等问题。SOFM 让获胜者的邻域一起学习,从而学到输入空间的拓扑;LVQ 用固定的第二层把多个子类合并为一类,能形成非凸、不连通的类,正确时拉近、错误时推远,LVQ2 进一步修正初始布局不利的情形。
| 规则 / 网络 | 公式 | 何时更新 |
|---|---|---|
| 无监督 Hebb | \(\mathbf{W}\leftarrow\mathbf{W}+\alpha\mathbf{a}\mathbf{p}^T\) | 输入、输出同时非零 |
| 带衰减 Hebb | \(\mathbf{W}\leftarrow(1-\gamma)\mathbf{W}+\alpha\mathbf{a}\mathbf{p}^T\),\(w^{\max}=\alpha/\gamma\) | 每步都衰减 |
| instar | \({}_i\mathbf{w}\leftarrow{}_i\mathbf{w}+\alpha a_i(\mathbf{p}-{}_i\mathbf{w})\) | 输出 \(a_i\neq0\) |
| Kohonen | \({}_i\mathbf{w}\leftarrow(1-\alpha){}_i\mathbf{w}+\alpha\mathbf{p}\),\(i\in X(q)\) | \(i\) 属于获胜集合 |
| outstar | \(\mathbf{w}_j\leftarrow\mathbf{w}_j+\alpha(\mathbf{a}-\mathbf{w}_j)p_j\) | 输入 \(p_j\neq0\) |
| instar 识别条件 | \(|\mathbf{w}||\mathbf{p}|\cos\theta\ge-b\) | — |
| 竞争层 | \(\mathbf{a}=\mathrm{compet}(\mathbf{W}\mathbf{p})\) 或 \(\mathrm{compet}(-|{}_i\mathbf{w}-\mathbf{p}|)\) | 只更新获胜者 |
| SOFM | Kohonen 规则作用于 \(N_{i^*}(d)=\{j:d_{ij}\le d\}\) | 获胜者及其邻域 |
| LVQ | 正确:\({}_{i^*}\mathbf{w}^1\mathrel{+}=\alpha(\mathbf{p}-{}_{i^*}\mathbf{w}^1)\);错误:\(\mathrel{-}=\) | 只更新获胜子类(LVQ2 再拉近正确子类) |
| 良心机制 | 赢家 \(b\leftarrow b-0.2\),输家 \(b\leftarrow0.9b\) | 每步 |
练习
基础
-
带衰减 Hebb 规则 \(\alpha=0.3\)、\(\gamma=0.1\),求权值上限;若 \(a_ip_j\) 在 0、1 间交替,上限是多少?(原书 E15.2、P15.1) 答案要点:\(\alpha/\gamma=3\);交替时 \(\alpha/(\gamma(2-\gamma))=0.3/0.19\approx1.58\)。
-
instar \({}_1\mathbf{w}=[1;-1;-1]\)、\(b=-2\),输入为 \(\pm1\) 的三维向量。哪些输入会激活它? 提示:内积 \(\ge2\) 只有 \([1;-1;-1]\) 本身(内积 3);与它差一个分量的向量内积为 1,不激活。
-
复核原书 P16.2 的六步竞争学习,写出每步的获胜者和更新后的权值,并指出死神经元。 答案要点:获胜者依次为 2、3、3、2、3、3;最终 \({}_2\mathbf{w}=[-0.974;0.112]\),\({}_3\mathbf{w}=[0.414;0.810]\),神经元 1 从未获胜。
-
证明输入与权值都归一化时,用负距离和用内积的竞争层选出同一个获胜者。(原书 E16.8) 提示:\(\|\mathbf{w}-\mathbf{p}\|^2=\|\mathbf{w}\|^2+\|\mathbf{p}\|^2-2\mathbf{w}^T\mathbf{p}\)。
-
Hamming 网络第 2 层若取 \(\varepsilon=3/4\),而 \(S=3\),构造一个使竞争失败的第一层输出。(原书 E16.1) 提示:\(\varepsilon>1/(S-1)=1/2\) 时,几个接近的值会在同一步全部被压到 0。例如 \(\mathbf{a}^2(0)=[1;0.95;0.9]\),一步后三个分量分别为 \(1-0.75\times1.85<0\)、\(0.95-0.75\times1.9<0\)、\(0.9-0.75\times1.95<0\),全部变成 0,没有赢家。
进阶
-
解释为什么 Kohonen 规则下,一个只赢得某簇样本的原型会收敛到该簇的(指数加权)均值;学习率固定为 \(\alpha\) 时,它的"有效样本数"约为多少? 答案要点:原型是赢得样本的 EMA,有效窗口约 \(1/\alpha\)(更精确地 \((2-\alpha)/\alpha\))。
-
用 LVQ 设计一个分类器,类 1 为 \(\{[-1;-1],[1;1]\}\),类 2 为 \(\{[1;-1],[-1;1]\}\),并说明为什么单层感知机做不到。(对应 XOR 例子与 E16.15)
-
修改 15.5 节的代码,把竞争层神经元数从 6 改为 3,并改用数据点初始化。识别率如何变化?再把特征加上"20 日成交量变化"(自行模拟与状态相关的成交量),观察震荡状态能否分出来。
-
在 15.5 节的 SOFM 中,把邻域半径固定为 0(即普通竞争学习),比较节点原型在链上是否仍然有序。解释原因。
原书推荐习题:第 15 章 P15.1、E15.1、E15.2(衰减与稳态);P15.2、E15.5、E15.6(instar 迭代);P15.4(识别边界);E15.9(outstar 模拟)。第 16 章 P16.2、E16.3(死神经元与顺序依赖);E16.4(良心机制);E16.8(距离与内积等价);E16.9、E16.10(竞争层与 SOFM 编程);E16.15(LVQ 设计);P16.7(归一化与幅度信息)。
原书对照
| 本章小节 | 原书内容 | PDF 页码 |
|---|---|---|
| 15.1.1 | 第 15 章 Theory and Examples、Simple Associative Network | p.574–578 |
| 15.1.2–15.1.3 | Unsupervised Hebb Rule、Hebb Rule with Decay | p.578–582 |
| 15.1.4–15.1.5 | Simple Recognition Network、Instar Rule、Kohonen Rule | p.582–588 |
| 15.1.6 | Simple Recall Network、Outstar Rule | p.589–593 |
| 第 15 章例题与习题 | P15.1–P15.5;E15.1–E15.9 | p.596–606;p.610–615 |
| 15.2 | 第 16 章 Hamming Network、Competitive Layer、Competitive Learning、Problems with Competitive Layers | p.616–625 |
| 15.3 | Competitive Layers in Biology、Self-Organizing Feature Maps | p.625–631 |
| 15.4 | Learning Vector Quantization、Improving LVQ (LVQ2) | p.631–636 |
| 第 16 章例题与习题 | P16.1–P16.7;E16.1–E16.18 | p.639–651;p.654–663 |
原书第 15、16 章正文中的部分交叉引用和演示程序编号(如 nnd13xx、nnd14xx)沿用第一版章号,本章已按第二版章号改写:联想学习为第 15 章,竞争网络为第 16 章,Grossberg 网络为第 18 章,ART 为第 19 章。