Commit graph Warrior_EA/AI/LayerDescription.mqh
Author SHA1 Message Date
AnimateDread
30206cbabc feat(ai): batch normalization between dense layers
The only bounded stage in the entire forward path was the sigmoid
classification head - every hidden stage is PRELU. That is a network with
no internal scale control, and the failure ordered exactly by depth: on
SP500 H1 the shallow perceptron held ~52% balanced accuracy while the
deepest topology sat on the 33.3% one-class floor, with the per-bar logit
spread decaying monotonically (0.45 -> 0.38 over ~200 eras) until the
evidence tilt fell under the class-prior tilt. That is the signature of
internal covariate shift, which chapter 6.1 of the reference book is
entirely about and which the NeuroNet_DNG engine addresses with a layer
this project never had.

Two mechanisms make this the right fix rather than more hyperparameter
nudging:
  - it decouples WEIGHT_DECAY from the learned function (van Laarhoven
    2017) - with a normalized layer downstream, decay can no longer grind
    the discriminative signal away, it only rescales the effective
    learning rate;
  - it is the precondition for ever running an unbounded logit head here.
    The 2026-07-27 attempt blew up (IS error 5.6e15) precisely because
    nothing upstream constrained scale.

Implementation notes:
  - CNeuronBatchNormOCL computes host-side rather than as a fourth copy of
    a kernel across Network.cl + WarriorCPU.cpp + WarriorDML.cpp. The math
    is elementwise O(n); this way it behaves identically on all four
    compute tiers, needs no DLL rebuild, and cannot drift between
    backends. Same precedent as the softmax+CCE gradient and the
    per-sample loss weighting, both computed in MQL5 for that reason.
  - Statistics are exponential moving, not a stored mini-batch: training
    is pure online SGD, one update per sample, so there is no batch to
    average over. BatchNormWindow is an EMA window length.
  - gamma/beta are excluded from weight decay, deliberately - decaying
    gamma toward zero is the exact pathology being fixed.
  - The layer self-sizes from whatever sits below it, because a conv/pool
    stage's output width is derived inside the CNet constructor and is not
    knowable to the topology builder.
  - Checkpoint capture/restore/blend carry gamma/beta and the running
    statistics alongside the dense matrix, so the plateau ladder cannot
    restore a mismatched pair.
  - SeedOutputLayerBias accepted only an exact defNeuronBaseOCL as the
    weight-carrying penultimate layer; with normalization enabled that is
    the batch-norm layer, so the cold-start bias seed would have silently
    stopped being applied.
  - Refuses to build, loudly, if a topology asks for normalization with no
    compute backend at all - rather than quietly training a different
    architecture than the one requested.

EnableBatchNorm (default on) and BatchNormWindow (1000 samples) are
inputs so the effect can be A/B'd without a recompile. Both feed the
weights-filename fingerprint, appended conditionally so existing non-BN
configs keep their fingerprints and are not forced to retrain.

Verified: analytic gradients match finite differences to 1.5e-7 relative
over 200 random cases; a faithful port of the full forward/backward chain
collapses to the 33.3% floor by era 4 without this layer and holds
36-43% with it. Compiles 0 errors, 0 warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 12:34:29 -04:00
AnimateDread
e4a154aa5e refactor(AI): split 8 self-contained classes out of the Network.mqh god-file
AI/Network.mqh was 5,805 lines / 18 classes in one file. Investigation
found method implementations for several classes (CNeuronBase/Pool/Conv,
CNeuronBaseOCL) hand-interleaved across thousands of lines - not safe to
split without risky manual reassembly. But 8 classes turned out to be
genuinely self-contained (declaration + every method body physically
contiguous, and only ever depended upon, never depending on anything
declared later): CConnection/CArrayCon, CNeuron, CDirectMLMy (+ its
WarriorDML.dll/WarriorCPU.dll #import blocks), CArrayLayer,
CLayerDescription, CBufferDouble, and CNeuronConvOCL/CNeuronPoolOCL.

Extracted each verbatim, via exact line-range extraction (not manual
retyping) to eliminate transcription risk, into its own AI/*.mqh file,
included from Network.mqh at the exact point each class used to sit -
preserving original declaration order exactly. Mathematically verified
byte-for-byte: reconstructing the original file from the 7 new files'
bodies + Network.mqh's remaining segments is line-for-line identical to
the pre-split git history. Compiled clean (MetaEditor, 0 errors/0
warnings) both before and after.

The remaining tangled classes (CNeuronBase, CNeuronPool, CNeuronConv,
CNet, CNeuronLSTM, CNeuronBaseOCL, CNeuronConvOCL/PoolOCL's shared base,
CNeuronLSTMOCL, COpenCLMy) stay in Network.mqh (now ~4,450 lines) -
splitting those safely needs deliberate per-method surgery, deferred to
a future dedicated pass rather than rushed into this one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 16:13:03 -04:00