kronos-mql5/Scripts/Kronos/KronosVerifyPredictorS1.mq5
2026-07-05 05:06:39 +00:00

185 lines
6.5 KiB
MQL5

//+------------------------------------------------------------------+
//| KronosVerifyPredictorS1.mq5 |
//| MMQ — Muhammad Minhas Qamar |
//| www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "MMQ — Muhammad Minhas Qamar"
#property link "https://www.mql5.com"
#property version "1.00"
#property script_show_inputs
#property strict
#include <Kronos\KronosPredictorS1.mqh>
#define KR_PRED_D_MODEL 512
#define KR_PRED_N_HEADS 8
#define KR_PRED_N_LAYERS 8
#define KR_PRED_FF_DIM 1024
#define KR_PRED_WEIGHT_DIR "kronos_weights\\predictor\\"
input string InpRefDir = "kronos_refs\\";
input int InpLookback = 256;
input double InpTol = 1e-3; // logits accumulate more rounding than recon; allow 1e-3
//+------------------------------------------------------------------+
//| Read a [rows,cols] float32 .bin into a matrix(double). |
//+------------------------------------------------------------------+
bool LoadF32Matrix(const string fname, ulong rows, ulong cols, matrix &out)
{
int h = FileOpen(fname, FILE_READ | FILE_BIN);
if(h == INVALID_HANDLE)
{ PrintFormat("LoadF32Matrix: cannot open %s (err %d)", fname, GetLastError()); return false; }
ulong n = rows * cols;
float buf[];
ArrayResize(buf, (int)n);
uint got = FileReadArray(h, buf, 0, (int)n);
FileClose(h);
if(got != n)
{
PrintFormat("LoadF32Matrix: short read %s", fname);
return false;
}
out = matrix::Zeros(rows, cols);
for(ulong r = 0; r < rows; r++)
for(ulong c = 0; c < cols; c++)
out[r][c] = (double)buf[r * cols + c];
return true;
}
//+------------------------------------------------------------------+
//| Read N float32 values from a .bin into a double[]. |
//+------------------------------------------------------------------+
bool LoadF32Vector(const string fname, int n, double &out[])
{
int h = FileOpen(fname, FILE_READ | FILE_BIN);
if(h == INVALID_HANDLE)
{ PrintFormat("LoadF32Vector: cannot open %s (err %d)", fname, GetLastError()); return false; }
float buf[];
ArrayResize(buf, n);
uint got = FileReadArray(h, buf, 0, n);
FileClose(h);
if(got != (uint)n)
{
PrintFormat("LoadF32Vector: short read %s", fname);
return false;
}
ArrayResize(out, n);
for(int i = 0; i < n; i++)
out[i] = (double)buf[i];
return true;
}
//+------------------------------------------------------------------+
//| Read N int32 values from a .bin into an int[]. |
//+------------------------------------------------------------------+
bool LoadI32Array(const string fname, int n, int &out[])
{
int h = FileOpen(fname, FILE_READ | FILE_BIN);
if(h == INVALID_HANDLE)
{ PrintFormat("LoadI32Array: cannot open %s (err %d)", fname, GetLastError()); return false; }
ArrayResize(out, n);
uint got = FileReadArray(h, out, 0, n);
FileClose(h);
if(got != (uint)n)
{
PrintFormat("LoadI32Array: short read %s", fname);
return false;
}
return true;
}
//+------------------------------------------------------------------+
//| Script entry point. |
//+------------------------------------------------------------------+
void OnStart()
{
Print("============ Kronos predictor decode_s1 verification ============");
const int L = InpLookback;
const int V = KR_PRED_VOCAB; // 1024
int s1[], s2[];
if(!LoadI32Array(InpRefDir + "s1_ids.bin", L, s1))
{
Print("ABORT: s1_ids.bin");
return;
}
if(!LoadI32Array(InpRefDir + "s2_ids.bin", L, s2))
{
Print("ABORT: s2_ids.bin");
return;
}
matrix stamp;
if(!LoadF32Matrix(InpRefDir + "x_stamp.bin", (ulong)L, 5, stamp))
{
Print("ABORT: x_stamp.bin");
return;
}
double ref[];
if(!LoadF32Vector(InpRefDir + "s1_logits_last.bin", V, ref))
{
Print("ABORT: s1_logits_last.bin");
return;
}
CKronosPredictorS1 pred;
if(!pred.Init(KR_PRED_WEIGHT_DIR, KR_PRED_N_LAYERS, KR_PRED_D_MODEL, KR_PRED_N_HEADS, KR_PRED_FF_DIM))
{ Print("ABORT: predictor Init failed"); return; }
Print("Predictor (s1) weights loaded.");
matrix s1_logits, context;
if(!pred.DecodeS1(s1, s2, stamp, s1_logits, context))
{ Print("ABORT: DecodeS1 failed"); return; }
PrintFormat("s1_logits %I64u x %I64u, context %I64u x %I64u",
s1_logits.Rows(), s1_logits.Cols(), context.Rows(), context.Cols());
if(s1_logits.Rows() != (ulong)L || s1_logits.Cols() != (ulong)V)
{ Print("ABORT: logits shape mismatch"); return; }
//--- compare LAST time-step logits (row L-1) to the reference vector
int last = L - 1;
double maxerr = 0.0, sumerr = 0.0;
int wcol = -1;
for(int j = 0; j < V; j++)
{
double e = MathAbs(s1_logits[last][j] - ref[j]);
sumerr += e;
if(e > maxerr)
{
maxerr = e;
wcol = j;
}
}
double meanerr = sumerr / (double)V;
PrintFormat("last-step s1 logits: max abs err = %.3e (col %d), mean abs err = %.3e", maxerr, wcol, meanerr);
if(wcol >= 0)
PrintFormat("worst cell: mql=%.6f ref=%.6f", s1_logits[last][wcol], ref[wcol]);
//--- crucial sanity: do MQL5 and reference pick the SAME argmax token?
int amx_mql = 0, amx_ref = 0;
double bm = s1_logits[last][0], br = ref[0];
for(int j = 1; j < V; j++)
{
if(s1_logits[last][j] > bm)
{
bm = s1_logits[last][j];
amx_mql = j;
}
if(ref[j] > br)
{
br = ref[j];
amx_ref = j;
}
}
PrintFormat("argmax token: mql=%d ref=%d %s", amx_mql, amx_ref,
(amx_mql == amx_ref ? "(MATCH)" : "(DIFFER!)"));
if(maxerr <= InpTol && amx_mql == amx_ref)
PrintFormat(">>> DECODE_S1 VERIFIED: max abs err %.3e <= tol %.3e, argmax matches. <<<", maxerr, InpTol);
else
Print(">>> DECODE_S1 MISMATCH: check embedding lookup/scale, temporal sum, "
"block count (8, not 7), final norm, or proj_s1 transpose. <<<");
Print("================================================================");
}
//+------------------------------------------------------------------+