Warrior_EA/AI
Repository files (latest commit first)
Filename Latest commit message Latest commit date
AnimateDread d30420e3f2 fix(batchnorm): bound the normalized value - a constant input feature was amplified 1e4x and pinned PAI's head to its rails
BN_MIN_STD = 1e-4 caps the per-unit gain at 1/1e-4 = 1e4, and the comment above
it states that as though it were a safety property. It is not. A unit whose
running variance is ~0 is a CONSTANT feature carrying no information, and
dividing its rounding noise by 1e-4 hands the next layer an activation of
several hundred. BN's contract is "output has ~unit variance"; a unit that
cannot supply that must contribute nothing, not the largest signal in the layer.

MEASURED, 2026-08-17 SP500 H4, four topologies on identical separate charts:

  model   spread   Neutral CHOSE   Neutral TIED   rail
  CONV     0.386        0.68%          0.10%      0.48%
  LSTM     0.392        0.63%          0.00%      0.00%
  HYB      0.376        1.79%          0.00%      0.01%
  PAI      0.192        0.09%         80.63%     99.99%

bn1's cached nx normed 1.38e4 over 800 units. PAI's SIGMOID head was on its
rails on 99.99% of bars, with Buy and Sell landing on the SAME rail so they
compared exactly equal, and ApplyClassificationSoftmax()'s strict-majority rule
reported that tie as Neutral on ~80% of bars.

So the long-running "PAI is heavily biased toward Neutral" was never a
class-prior problem: the net CHOSE Neutral on 0.09% of bars. It was float
equality on a saturated head. The 331ab29 counters answered it on their first
run.

PAI-only because it is the one topology whose FIRST batch norm sits on the raw
800-dim input vector - CONV/LSTM/CONVLSTM all have a conv or LSTM stage in
front, so their first BN sees a learned representation with no degenerate
units. That asymmetry was already on file as a suspicion; this is the mechanism.

FIX, mirrored in both backends (host NeuronBatchNorm.mqh and device Network.cl):

  forward   nx = clamp(delta/sd, -BN_MAX_NX, +BN_MAX_NX), BN_MAX_NX = 8
  backward  if the forward bound this unit, the output stopped depending on the
            input, so d(nx)/dx = 0 and NO gradient passes

The backward half is not optional. g is divided by the same sd the forward
multiplies by, so a degenerate unit gets its GRADIENT amplified 1e4x too - the
"receives gradients divided by sqrt(var) ~ 500" pathology already noted in
Network.cl's Adam kernel. Bounding only the forward would move the explosion
downstream.

8 sigma is inert on anything healthy (|nx| > 8 is a ~1e-15 event under
normality); it binds only on degenerate units, which is the entire point. Same
clamp-to-range idiom the activation derivatives beside it already use.
SelfCheckBnForward/SelfCheckBnHiddenGrad already prove host against kernel, and
BN_OPT_NX was already consumed in the backward for the gamma gradient, so the
new read adds no lifetime assumption.

Expect PAI to change behaviour and CONV/LSTM/CONVLSTM not to (their rail rate is
~0%, so the clamp never binds). No .nnw format or fingerprint change.

ALSO: print the zero-skill reference on the era line. m_oosWinLongTotal and
m_oosWinShortTotal have been accumulated for a long time and NEVER printed,
which is why three separate topologies all sitting at 62% read as a mysterious
coincidence rather than the obvious base rate. It is not a coincidence: with the
target (1.70 ATR) nearer than the stop (3.07 ATR), BOTH sides win on 24.5% of
bars, so winLong+winShort covers ~124% of them and a no-edge caller collects
62.1% whichever way it calls - against a 64.3% break-even. Derived from this
run's own label counts: (11329 - 2776 + 2*2776) / (2*11350) = 62.14%.

Every win rate on that line must be read against this, not against 50%.

NOT COMPILED - user compiles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-17 00:21:51 -04:00
..
Impl fix(diagnostics+calibration): the frozen-layer reading was a broken ruler; gate the operating point on a null of the maximum 2026-08-16 23:44:26 -04:00
ArrayLayer.mqh refactor(AI): split 8 self-contained classes out of the Network.mqh god-file 2026-07-18 16:13:03 -04:00
BufferDouble.mqh fix: training-stability audit fixes F1/F2/F3/F5 - unbiased shuffle, real plateau escapes, fresh optimizer state on restore, pure OOS metric 2026-08-09 10:54:09 -04:00
LayerDescription.mqh feat(ai): batch normalization between dense layers 2026-07-29 12:34:29 -04:00
Network.cl fix(batchnorm): bound the normalized value - a constant input feature was amplified 1e4x and pinned PAI's head to its rails 2026-08-17 00:21:51 -04:00
Network.mqh fix: live trades now use the geometry the gate certifies; perf: BN kernels 2026-08-09 17:51:40 -04:00
NeuronBatchNorm.mqh fix(batchnorm): bound the normalized value - a constant input feature was amplified 1e4x and pinned PAI's head to its rails 2026-08-17 00:21:51 -04:00
NeuronCPU.mqh fix: the Adam second moment was never Adam - all four tiers 2026-08-09 14:02:35 -04:00
NeuronDirectML.mqh feat: mini-batch gradient accumulation (F4), front-end-aware capacity budget (F6), split Wyckoff categoricals (N1) 2026-08-09 11:48:03 -04:00
NeuronOCLConvPool.mqh fix: dense backprop read the weight matrix transposed - on every backend 2026-08-11 18:06:09 -04:00
NeuronPrimitives.mqh fix: correct CLayer::CreateElement signature to prevent model load failures 2026-07-25 12:02:38 -04:00