Warrior_EA/AI/NeuronCPU.mqh

161 lines
8.2 KiB
MQL5
Raw Permalink Normal View History

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
//+------------------------------------------------------------------+
//| NeuronCPU.mqh |
//| AnimateDread |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
refactor(ai): remove the DirectML/D3D12 GPU compute tier (S1.5) Three backends left, as the operator specified: OpenCL, the CPU DLL, and pure MQL5. CDirectMLMy was a two-tier wrapper (GPU via WarriorDML.dll, CPU via WarriorCPU.dll) whose name only ever named the tier being removed here; the CPU DLL tier - the one actually used on the training machine (no OpenCL, no DirectML) - is untouched. AI/NeuronDirectML.mqh -> AI/ComputeDll.mqh: dropped the DML_* #import block and COMPUTE_TIER_GPU (checked first that nothing persists the enum value and only one external site reads .Tier() - safe), collapsed every tier==CPU?CPU_x():DML_x() ternary to a straight CPU_x() call. Renamed CDirectMLMy->CComputeDll, InitDirectML()->InitComputeDll(), member directml/DirectML->computeDll/ComputeDll across every AI/ file that touched a neuron/net backend plus Topology.mqh/OnlineLearning.mqh. NetBuild.mqh's InitComputeDll also lost the dead D3D12 error-code switch and the now-impossible GPU-tier log branch. Verified via per-file brace-balance diff against HEAD and a whole-repo grep for every removed symbol (CDirectMLMy/InitDirectML/ COMPUTE_TIER_GPU/DML_*) - the only surviving hit is an intentional historical-note comment in the new file's header. DirectML\WarriorDML.cpp/.h and its build scripts are now orphaned C++ source, left in place pending an operator decision. Architecture docs (AI_NETWORK.md, Warrior_EA_System_Overview.md, etc.) still describe the 4-backend/GPU-tier shape and are not updated in this pass. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 19:32:09 -04:00
//| CNeuron - the plain-CPU (no DLL/OpenCL) dense neuron, |
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
//| last-resort fallback tier. Needs CNeuronBase (AI\Network.mqh) |
//| and CLayer/CConnection already declared - included from |
//| Network.mqh at the exact point CNeuron used to sit, so ordering |
//| matches the original file. Extracted verbatim (SOLID cleanup) - |
//| no logic changes. |
//+------------------------------------------------------------------+
class CNeuron : public CNeuronBase
{
private:
virtual bool feedForward(CLayer *prevLayer);
virtual bool calcHiddenGradients(CLayer *&nextLayer);
virtual bool updateInputWeights(CLayer *prevLayer);
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
public:
CNeuron(void) {};
~CNeuron(void) { Connections.Shutdown(); }
//---
virtual bool calcOutputGradients(double targetVals);
virtual double sumDOW(CLayer *&nextLayer) ;
virtual int Type(void) const { return defNeuron; }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::updateInputWeights(CLayer *prevLayer)
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
{
if(CheckPointer(prevLayer) == POINTER_INVALID)
return false;
//---
double lt = g_eta * sqrt(1 - pow(AdamBeta2, t)) / (1 - pow(AdamBeta1, t));
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
int total = prevLayer.Total();
for(int n = 0; n < total && !IsStopped(); n++)
{
CNeuron *neuron = prevLayer.At(n);
CConnection *con = neuron.Connections.At(m_myIndex);
if(CheckPointer(con) == POINTER_INVALID)
continue;
if(optimization == SGD)
con.weight += con.deltaWeight = (gradient != 0 ? g_eta * neuron.getOutputVal() * gradient : 0) + (con.deltaWeight != 0 ? alpha*con.deltaWeight : 0);
else
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
{
//--- Per-WEIGHT gradient (neuron gradient x presynaptic output), matching the SGD branch
//--- above and every native backend's Adam kernel (`grad = g[i] * inp` in
//--- CPU_UpdateWeightsAdam).
double g = gradient * neuron.getOutputVal();
refactor(stdlib): adopt Math\Stat for the deploy gate's normal tail; retire the b1/b2/lr/momentum macros The gate's NormalUpperTail was a hand-rolled Abramowitz & Stegun 26.2.17 approximation. Its own comment gave the reason - "drags a chain of headers behind it" - and that turned out to be one file: Math\Stat\Normal.mqh includes only Math.mqh, which includes nothing. Swapped for Cody's rational approximation in the library (~18 significant digits vs |error| < 7.5e-8). No past verdict changes: at the z the gate operates on, the difference is orders of magnitude below DEPLOY_FAMILY_WISE_ALPHA. Adopting it needed the four bare macros in AI\Network.mqh gone first. "#define b1 AdamBeta1" collides with an identifier in Math.mqh, so the include would have macro-expanded the library's own local and failed to compile - the same landmine that made the original author rename the approximation's coefficients to ntB1..ntB5 rather than use the reference's b1..b5. lr, b2 and momentum are the same class of hazard: single-token global macros in a 52k-line codebase. All four now resolve to the input names they always aliased, which is a pure textual identity - verified zero bare occurrences remain. Also: - SelectionSort over the buffered signals was O(n^2) with an O(n^2) count of StructToTime calls, because the comparison rebuilt both datetimes from the six int date fields every time. Now materialises the keys once and does an insertion sort; ArraySort cannot permute a struct array. IsEarlier goes with it, MakeDateTime becomes SignalTime. - Seven FileOpen sites lacked FILE_SHARE_READ|FILE_SHARE_WRITE, including AtomicWriteBegin, which stages every model save. All 43 sites now carry them - an exclusive open fails outright when another process holds the path, which here has meant a silently skipped save. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 19:31:36 -04:00
con.mt = AdamBeta1 * con.mt + (1 - AdamBeta1) * g;
// Stores sqrt(...) directly into vt (not the raw second-moment estimate) to exactly match
// every native backend's Adam recursion (AI\Network.cl's UpdateWeightsAdam, WarriorDML.cpp,
fix: the Adam second moment was never Adam - all four tiers Root cause of the B=32 regression, and it predates F4 entirely. Every Adam kernel stored v already square-rooted and then fed that stored value back in as if it were the variance: v_new = sqrt(b2 * v_old + (1 - b2) * g^2) That recursion has a fixed point at v ~= b2 = 0.999 for ANY gradient below unit scale, so the denominator stops tracking the gradient and Adam degrades into plain SGD with lr = lt. Measured against the shipped WarriorCPU.dll (batch_accum_check.cpp, TestOptimizerScaleInvariance), 4000 steps of a constant gradient: 3285x less displacement at |g|=1e-5 than at |g|=1, where a scale-invariant optimizer gives the same distance for both. After the fix all six magnitudes read 1.199 and v tracks |g| exactly. It hit conv/LSTM specifically because they sit behind a batch-norm with running variance ~2.6e+05, so their gradients arrive divided by ~500 - deep in the degraded regime - while the dense stack near the loss stayed in the working one. In situ on SP500 H1: lstm1 dW/W 2.62/10.0/7.14% -> 0.024/0.022/ 0.003%, conv1 decaying to 0.000% by era 30. NeuronBatchNorm.mqh already squared v back for gamma/beta and its comment named the kernels as wrong, which is exactly why gamma/beta kept training while the stages behind froze. Persisted .nnw needs no migration - v keeps its std-dev meaning. Also, the two ways F4 exposed it, both mine: - No LR compensation for B fewer steps per era. sqrt(B) for adaptive methods (Krizhevsky 2014; Granziol et al. 2022), applied once in InitialEtaForOptimizer(). Linear scaling (Goyal et al. 2017) is for SGD. - Plateau patience denominated in eras, so raising B made the ladder 32x more impatient in its only unit. PAI converged at era 41 on ~49k updates where the same config had been finding new bests at era 1028. TrainPlateauPatienceEras() stretches it by the same sqrt(B). TRAIN_BATCH_SIZE 32 -> 8 so the patience stretch stays affordable (8 -> 23 eras per stage, not 8 -> 45). Both helpers are identities at B=1. Deploy gate: DEPLOY_MIN_SIDE_RECALL_PCT (10%) folded into tradeableOK. The perceptron reported Sell:0% recall in all 41 eras, cleared the floor on Buy alone at 36.6% vs 34% chance, deployed, and sprayed buy arrows. Folded into the ranking key rather than checked at deploy time so a one-sided era cannot become best-so-far in the first place. Deinit: the arrow purge now runs BEFORE ExtPanel.Destroy(), an unbounded CAppDialog teardown that sat ahead of it - the same ordering inversion the rule there exists to prevent. CONV was force-terminated 4.8 s into OnDeinit (vs ~1.1 s for the three that finished) having reached none of its cleanup, so its arrows stayed on the chart. Steps are now timed in the log. PurgeChart's verification rescan filtered on OBJ_ARROW, the same blind spot as the bulk delete, so "persisted 10 ... cleared 0" passed silently. It now walks every object type and reports the object counts when both are zero. Both build variants compile 0 errors / 0 warnings; both DLLs rebuilt. FORCES A RETRAIN (already forced by N1) and both DLLs must ship with the .ex5. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 14:02:35 -04:00
// WarriorCPU.cpp), and squares it back before re-entering that recursion - which IS the
// textbook raw-variance recursion, just carried in std-dev form so the stored value can be
// the denominator directly. Until 2026-08-09 all four tiers agreed on a version that fed
// the stored sqrt back in as if it were the variance; they agreed, and they were all wrong
// (see Network.cl for the measurement). Keep these four in lockstep either way: a tier that
// diverges here silently produces different weights from the same data.
refactor(stdlib): adopt Math\Stat for the deploy gate's normal tail; retire the b1/b2/lr/momentum macros The gate's NormalUpperTail was a hand-rolled Abramowitz & Stegun 26.2.17 approximation. Its own comment gave the reason - "drags a chain of headers behind it" - and that turned out to be one file: Math\Stat\Normal.mqh includes only Math.mqh, which includes nothing. Swapped for Cody's rational approximation in the library (~18 significant digits vs |error| < 7.5e-8). No past verdict changes: at the z the gate operates on, the difference is orders of magnitude below DEPLOY_FAMILY_WISE_ALPHA. Adopting it needed the four bare macros in AI\Network.mqh gone first. "#define b1 AdamBeta1" collides with an identifier in Math.mqh, so the include would have macro-expanded the library's own local and failed to compile - the same landmine that made the original author rename the approximation's coefficients to ntB1..ntB5 rather than use the reference's b1..b5. lr, b2 and momentum are the same class of hazard: single-token global macros in a 52k-line codebase. All four now resolve to the input names they always aliased, which is a pure textual identity - verified zero bare occurrences remain. Also: - SelectionSort over the buffered signals was O(n^2) with an O(n^2) count of StructToTime calls, because the comparison rebuilt both datetimes from the six int date fields every time. Now materialises the keys once and does an insertion sort; ArraySort cannot permute a struct array. IsEarlier goes with it, MakeDateTime becomes SignalTime. - Seven FileOpen sites lacked FILE_SHARE_READ|FILE_SHARE_WRITE, including AtomicWriteBegin, which stages every model save. All 43 sites now carry them - an exclusive open fails outright when another process holds the path, which here has meant a silently skipped save. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 19:31:36 -04:00
con.vt = sqrt(AdamBeta2 * con.vt * con.vt + (1 - AdamBeta2) * g * g);
con.deltaWeight = MathMax(-MAX_WEIGHT_DELTA, MathMin(MAX_WEIGHT_DELTA, lt * con.mt / (con.vt > 0 ? con.vt : lt * 10) - lt * WEIGHT_DECAY * con.weight));
// No sign-agreement gate (removed 2026-07): gating each step on agreement with the CURRENT
// sample's gradient sign rectified the one-hot softmax-CCE stream - rare large true-class
// positives (1/3 of samples), frequent small wrong-class negatives (2/3) - into a permanent
// downward ratchet on every output neuron, sinking all three logits into sigmoid saturation
// together (the all-Neutral collapse; IS error frozen at sqrt(1/3)=0.58). The stale-step
// overshoot it guarded against is covered by the MAX_WEIGHT_DELTA clip, AdamW WEIGHT_DECAY
// and shuffle-interleaved oversampling. Removed from all four backends in sync (WarriorCPU
// .cpp / WarriorDML.cpp / Network.cl mirror this).
con.weight += con.deltaWeight;
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
}
// Mirrors AI\Network.cl's MAX_WEIGHT clamp (see that file's Conv/LSTM Adam kernels) - without
// it a gradient spike (e.g. from class-balance oversampling replaying the same rare-class bar
// several times in a row - see Train()'s reps loop) can drive a weight to +-Infinity; the next
// Adam step then divides Infinity by Infinity (mt/vt both Inf) producing NaN, which propagates
// through every FeedForward sum that touches it and never recovers, since Adam(NaN)=NaN forever
// after. That silently freezes the whole network's output at NaN - manifesting as every bar
// classifying to whatever the "can't decide" default is (e.g. all-Neutral, 0 Buy/Sell) with no
// error ever surfaced, since NaN comparisons are simply always false.
con.weight = MathMax(-MAX_WEIGHT, MathMin(MAX_WEIGHT, con.weight));
}
if(optimization == ADAM)
t++;
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CNeuron::sumDOW(CLayer *&nextLayer)
{
double sum = 0.0;
int total = nextLayer.Total() - 1;
for(int n = 0; n < total; n++)
{
CConnection *con = Connections.At(n);
if(CheckPointer(con) == POINTER_INVALID)
continue;
double weight = con.weight;
if(weight != 0)
{
CNeuron *neuron = nextLayer.At(n);
sum += weight * neuron.gradient;
}
}
return sum;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::calcHiddenGradients(CLayer *&nextLayer)
{
//--- sumDOW * activation derivative, matching CNeuronConv::calcHiddenGradients (AI\Network.mqh)
//--- and the CalcHiddenGradient kernels in all three native backends.
gradient = sumDOW(nextLayer) * activationFunctionDerivative(outputVal);
return true;
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
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::calcOutputGradients(double targetVal)
{
//--- Deliberately NOT multiplied by activationFunctionDerivative(outputVal): for TANH that
//--- factor is (1-out^2), which vanishes as outputVal approaches +-1 - exactly where this neuron
//--- needs to converge for a +-1 target (e.g. the buy/sell extremes of a single-neuron
//--- regression head), stalling training right when it matters most.
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
double delta = (targetVal > 1 ? 1 : targetVal < -1 ? -1 : targetVal) - outputVal;
gradient = delta;
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CNeuron::feedForward(CLayer *prevLayer)
{
if(CheckPointer(prevLayer) == POINTER_INVALID || prevLayer.Type() != defLayer)
return false;
//---
prevVal = outputVal;
double sum = 0.0;
int total = prevLayer.Total();
for(int n = 0; n < total && !IsStopped(); n++)
{
CNeuron *temp = prevLayer.At(n);
double val = temp.getOutputVal();
if(val != 0)
{
CConnection *con = temp.Connections.At(m_myIndex);
if(CheckPointer(con) == POINTER_INVALID)
continue;
sum += val * con.weight;
}
}
outputVal = activationFunction(MathMin(MathMax(sum, -18), 18));
//---
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+