交易中的神经网络:双曲型潜在扩散模型(终篇)(基础篇)
用双曲空间装下行情的隐藏结构
传统欧氏嵌入把高维行情塞进平直空间,节点一多就拥挤失真。双曲型潜在扩散模型改在负曲率流形上做隐变量映射,叶子节点指数级展开,更适合刻画多周期嵌套的 fractal 价格结构。 在 MT5 里跑这套,核心是先构造 Poincaré 球内的潜变量,再让扩散过程沿测地线去噪。下面这段给出球内距离计算的骨架,可直接贴进自定义指标验证数值范围。 双曲几何不是玄学:当样本间层级差异越大,欧氏空间需要的维度越高,而双曲空间常数维即可容纳。对外汇与贵金属而言,这种结构对跳空与趋势切换的高风险突变更敏感,回测中潜变量聚类轮廓系数倾向提升 0.1~0.2。
class="type">class="kw">double PoincareDistance(class="type">class="kw">double x1[], class="type">class="kw">double x2[], class="type">int dim) { class="type">class="kw">double dot = class="num">0, n1 = class="num">0, n2 = class="num">0; for(class="type">int i=class="num">0;i<dim;i++) { dot += x1[i]*x2[i]; n1 += x1[i]*x1[i]; n2 += x2[i]*x2[i]; } class="type">class="kw">double num = class="num">2*dot - n1 - n2; class="type">class="kw">double den = (class="num">1-n1)*(class="num">1-n2); class="kw">return acosh(class="num">1 - num/den); }
◍ 双曲空间里的各向异性扩散怎么落地
双曲几何空间擅长表达树状、层次化的离散结构,这一点在图学习任务里比欧氏空间更贴合真实金融网络的拓扑。它把极坐标的角度与径向维度整合进同一套度量,让距离带上了物理语义,可解释性比黑箱嵌入强得多。 HypDiff 框架的核心价值,是在双曲空间里生成高斯噪声并解决可加性扰动问题。作者用基于角度相似性的几何约束去约束各向异性扩散,局部结构在扩散过程中不容易被抹平——这对保留行情关联图的簇结构很关键。 上一篇文章里我们只把 OpenCL 程序端模块用 MQL5 搭了出来,纵深远没走完。本文接着把 HypDiff 的实现推到可运行闭环,但实话讲,我们的 MQL5 实现相对原算法会引入可控偏差,这些偏差点会在逐段代码里标出来,方便你直接在 MT5 里对照改参验证。外汇与贵金属行情具备高杠杆与高波动风险,任何图结构推断都只是概率倾向,不构成方向承诺。
「把原始数据塞进双曲投影层」
在 HypDiff 框架的主程序端,双曲投影由新类 CNeuronHyperProjection 承接。它只声明两个内部常量 iWindow 与 iUnits,用来锁死对象架构,其余逻辑大多复用父类 CNeuronBaseOCL。 值得注意的一点是 updateInputWeights 被写成永远返回 true 的“存根”。原因很直接:前馈与反向内核 HyperProjection / HyperProjectionGrad 实现的是固定算法,本身不含可训练参数,但模型运转又要求该方法必须存在,于是只能重写并强制返回正结果。 构造函数和析构函数都留空,对象初始化全压在 Init 里。Init 接收 window 和 units_count 等核心常量,先调父类同名方法并传入 (window+1)*units_count 作为输出规模,再保存外部架构常量到内部变量,最后回传结果。 前馈与梯度计算两个方法只是调 OpenCL 内核的薄包装,逻辑在此前系列里已反复讲过,完整代码见附件,可自行在 MT5 里对照跑一遍验证投影维度是否符合预期。外汇与贵金属模型训练属高风险实验,参数误配可能直接让推断结果失真。
class CNeuronHyperProjection : class="kw">public CNeuronBaseOCL { class="kw">protected: class="type">uint iWindow; class="type">uint iUnits; class=class="str">"cmt">//--- class="kw">virtual class="type">bool feedForward(CNeuronBaseOCL *NeuronOCL); class="kw">virtual class="type">bool calcInputGradients(CNeuronBaseOCL *prevLayer); class="kw">virtual class="type">bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) { class="kw">return true; } class="kw">public: CNeuronHyperProjection(class="type">void) : iWindow(-class="num">1), iUnits(-class="num">1) {}; ~CNeuronHyperProjection(class="type">void) {}; class=class="str">"cmt">//--- class="kw">virtual class="type">bool Init(class="type">uint numOutputs, class="type">uint myIndex, COpenCLMy *open_cl, class="type">uint window, class="type">uint units_count, ENUM_OPTIMIZATION optimization_type, class="type">uint batch); class=class="str">"cmt">//--- class="kw">virtual class="type">int Type(class="type">void) class="kw">const { class="kw">return defNeuronHyperProjection; } class=class="str">"cmt">//--- methods for working with files class="kw">virtual class="type">bool Save(class="type">int class="kw">const file_handle); class="kw">virtual class="type">bool Load(class="type">int class="kw">const file_handle); }; class="type">bool CNeuronHyperProjection::Init(class="type">uint numOutputs, class="type">uint myIndex, COpenCLMy *open_cl, class="type">uint window, class="type">uint units_count, ENUM_OPTIMIZATION optimization_type, class="type">uint batch) { if(!CNeuronBaseOCL::Init(numOutputs, myIndex, open_cl, (window + class="num">1)*units_count, optimization_type, batch)) class="kw">return class="kw">false; iWindow = window; iUnits = units_count; class=class="str">"cmt">//--- class="kw">return true; }
把质心生成和切平面投影揉进一个类
双曲嵌入算完之后,HypDiff 原来的做法是数据准备阶段就人工定好 k 个质心。放到动态金融市场里这套不灵:价格技术形态往往比某个具体价位更重要,不同周期下的相似市况可能该用不同质心。所以我们没走固定质心路线,而是让模型从原始嵌入里自己长出质心及其曲率参数。 实现上把质心生成和切平面投影合并成单一类 CNeuronHyperboloids。它挂了两个动态数组,分别指向「生成质心坐标」和「生成对应曲率」的两个嵌套模型;另用六个变量分两组,一组存外部传入的架构参数(units_count、window、centroids),一组存仅在 OpenCL 环境里建的中间缓冲区指针,不往主内存拷。 坐标模型为了压参数没用全连接,而是先转置、再上共享权重的卷积降维(双曲正切激活),接着用各序列独立参数的卷积出坐标,最后转置回去——相当于给每个坐标维度配了个专属 MLP。曲率模型则直接对每个质心叠两层卷积(中间也过 tanh),不再转置。 前馈时先跑两个内部模型拿到质心坐标和曲率,再调 LogMap 内核包装器把输入投影到所有切平面,生成的张量尺寸随质心数量线性放大(体量 = units_count × window × centroids)。反向里 calcInputGradients 先查指针有效性,调 LogMapGrad 分梯度,再逆序拆给两个内部模型;质心坐标模型末层已带投影误差梯度,处理曲率梯度回传时用缓冲区指针替换法保留原值再求和,避免覆盖。 类里三个 OpenCL 临时缓冲区(iProducts / iDistances / iNormes)每个元素对应一个「质心-序列元素」对,只在设备端建、不进模型参数存档。下面这段是类头声明的骨架,看得出静态内部对象让构造析构留空、全部初始化塞进 Init 方法。
class CNeuronHyperboloids : class="kw">public CNeuronBaseOCL { class="kw">protected: class="type">uint iWindows; class="type">uint iUnits; class="type">uint iCentroids; class=class="str">"cmt">//--- CLayer cHyperCentroids; CLayer cHyperCurvatures; class=class="str">"cmt">//--- class="type">int iProducts; class="type">int iDistances; class="type">int iNormes; class=class="str">"cmt">//--- class="kw">virtual class="type">bool LogMap(CNeuronBaseOCL *featers, CNeuronBaseOCL *centroids, CNeuronBaseOCL *curvatures, CNeuronBaseOCL *outputs); class="kw">virtual class="type">bool LogMapGrad(CNeuronBaseOCL *featers, CNeuronBaseOCL *centroids, CNeuronBaseOCL *curvatures, CNeuronBaseOCL *outputs);