Warrior_EA/AI_NETWORK.md
AnimateDread 8d6842bbbf fix(ai): fold in the rest of the AI/Impl split - previous commit's git add aborted silently
A bad pathspec in a multi-file `git add` made the whole invocation a no-op except for
the 4 deletions already staged from an earlier `git rm` - Network.mqh's new inline
declarations, AI_NETWORK.md's table update, and the 4 new AI/Impl/*.mqh bodies never
landed in 46523dc. Same content already compiled clean; this just gets it into the
index. Tree is correct as of this commit; 46523dc alone is not.
2026-08-23 21:05:52 -04:00

5.6 KiB

AI/ — neural network subsystem

The engine behind the four AI signal modules (CSignalPAI, CSignalCONV, CSignalLSTM, CSignalHYBRID). It is a from-scratch MQL5 network — no external ML runtime — with four interchangeable compute tiers behind one interface.

File layout

AI\Network.mqh is the entry point and the only file anything outside AI\ includes. It holds declarations only: every neuron/layer/net class, the compile-time constants, and the nested include chain that orders them. Each nested #include sits exactly where its base class becomes visible, so that order is a dependency graph, not a preference — do not reorder it.

file holds
Network.mqh every class declaration, tuning constants, include chain
Network.cl OpenCL kernels (see below)
ArrayLayer.mqh CArrayLayer — the layer collection
LayerDescription.mqh CLayerDescription — the topology descriptor
BufferDouble.mqh CBufferDouble — host/device buffer

Method bodies live in AI\Impl\, included at the bottom of Network.mqh after every declaration. This is a pure relocation — a body cannot run during compilation, and every declaration it could reference is already visible above it.

AI\Impl\ holds
NeuronPrimitives.mqh CConnection / CArrayCon — weight storage
NeuronBase.mqh CNeuronBase — init, forward, gradients, activation, persistence
NeuronCPU.mqh CNeuron — pure-MQL5 dense neuron
NeuronConvPool.mqh CNeuronConv, CNeuronPool
NeuronLSTM.mqh CNeuronLSTM — gate layers, BPTT
Layer.mqh CLayer — element construction from a descriptor or a .nnw stream
NetBuild.mqh CNet lifecycle: topology construction, OpenCL init
NetForward.mqh feedForward, backProp, getResults, logit adjustment
NetPersistence.mqh CNet::Save / CNet::Load — the .nnw format
NetWeights.mqh EMA blend, in-memory snapshot/restore, per-layer learning report
NeuronOCLBase.mqh CNeuronBaseOCL
NeuronOCLConvPool.mqh CNeuronConvOCL, CNeuronPoolOCL
NeuronBatchNorm.mqh CNeuronBatchNormOCL — host-side batch norm, all tiers
NeuronOCLLSTM.mqh CNeuronLSTMOCL — sequence LSTM, fused kernels, BPTT caches

Compute tiers

Selected once at construction and logged; each layer runs entirely on one tier.

  1. OpenCLNetwork.cl, compiled from the #resource at startup.
  2. DirectMLWarriorDML.dll (D3D12 compute).
  3. CPU DLLWarriorCPU.dll, a threaded fallback. Thread count is fixed at CPU_THREADS_PER_NETWORK per net rather than a share of the machine; see the comment on that constant for why a machine-wide budget was wrong.
  4. Pure MQL5 — no DLL, no GPU. Single backtests run here so a Market build (which strips every #import) is still able to infer.

A Market build (WARRIOR_MARKET_BUILD) compiles tiers 2 and 3 out entirely.

Classes

  • CNet — owns the layer stack, the forward/backward passes and .nnw persistence. Note that a .nnw pins the architecture, not just the weights: Save writes each layer's activation and Load restores it, so a head activation changed in source only ever reaches a brand-new topology. EnforceOutputActivation() re-asserts it after every load.
  • CLayer / CArrayLayer — neuron containers; CreateElementScaled() is the single construction point for every neuron type, from a descriptor or from a file stream.
  • CNeuronBaseCNeuron / CNeuronPool / CNeuronConv / CNeuronLSTM — the pure-MQL5 family.
  • CNeuronBaseOCLCNeuronLSTMOCL / CNeuronConvOCL / CNeuronPoolOCL / CNeuronBatchNormOCL — the accelerated family. Despite the OCL suffix these also drive the DirectML and CPU-DLL tiers.

ENUM_ACTIVATION is NONE, TANH, SIGMOID, PRELU; ENUM_OPTIMIZATION is SGD, ADAM. NativeActivationCode() translates to the int code the backends share — and deliberately makes NONE fall through every backend switch.

Network.cl

22 kernels in four groups: dense (FeedForward, CaclOutputGradient, CaclHiddenGradient, UpdateWeightsMomentum/Adam), conv/pool (FeedForwardConv, FeedForwardProof, CalcHiddenGradientConv, CalcInputGradientProof, UpdateWeightsConv*), single-step LSTM (LSTM_Gates, LSTM_State, LSTM_*Gradient) and sequence LSTM (LSTM_SeqStep*, LSTM_UpdateWeights*).

Two invariants worth knowing before touching them:

  • MIN_ACTIVATION_DERIVATIVE (1.0e-3f) floors every LSTM gate derivative in both gradient kernels. It is already there — do not "add" it.
  • Kernel math is mirrored in DirectML\WarriorCPU.cpp and WarriorDML.cpp. A change to one is a change to all three, or the tiers silently diverge.

Usage

CNet *net = new CNet(topology);   // CArrayObj of CLayerDescription
net.feedForward(inputs);          // CArrayDouble
net.backProp(targets, weight);
net.getResults(out);
net.Save(path, ...); net.Load(path, ...);

The 3-output classification case is special-cased in backProp/backPropOCL: it computes a joint softmax + cross-entropy gradient across all three neurons rather than three independent per-neuron deltas.

Known gaps

  • No unit tests. Changes are validated by compile + a live era's dW/W line (CNet::LayerLearningReport), which is the only reliable check that a layer is actually receiving gradient in the assembled net.
  • No dedicated SoftMax layer; the head is Dense(SIGMOID) with the gradient short-circuited. See REFACTOR_NOTES.md §G for why, and for what would have to move together to change it.