220 lines
7.2 KiB
MQL5
220 lines
7.2 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| KronosVerifyPredictorS2.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> // DecodeS1 -> context, s1_logits
|
||
|
|
#include <Kronos\KronosPredictorS2.mqh> // DecodeS2 (cross-attn)
|
||
|
|
|
||
|
|
#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 = 2e-3; // s2 = s1 pipeline + cross-attn; allow a bit more
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| 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("open fail %s (%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("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 flat double[]. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
bool LoadF32Flat(const string fname, int n, double &out[])
|
||
|
|
{
|
||
|
|
int h = FileOpen(fname, FILE_READ | FILE_BIN);
|
||
|
|
if(h == INVALID_HANDLE)
|
||
|
|
{
|
||
|
|
PrintFormat("open fail %s (%d)", fname, GetLastError());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
float buf[];
|
||
|
|
ArrayResize(buf, n);
|
||
|
|
uint got = FileReadArray(h, buf, 0, n);
|
||
|
|
FileClose(h);
|
||
|
|
if(got != (uint)n)
|
||
|
|
{
|
||
|
|
PrintFormat("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("open fail %s (%d)", fname, GetLastError());
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
ArrayResize(out, n);
|
||
|
|
uint got = FileReadArray(h, out, 0, n);
|
||
|
|
FileClose(h);
|
||
|
|
if(got != (uint)n)
|
||
|
|
{
|
||
|
|
PrintFormat("short read %s", fname);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Script entry point. |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
void OnStart()
|
||
|
|
{
|
||
|
|
Print("============ Kronos predictor decode_s2 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");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if(!LoadI32Array(InpRefDir + "s2_ids.bin", L, s2))
|
||
|
|
{
|
||
|
|
Print("ABORT s2_ids");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
matrix stamp;
|
||
|
|
if(!LoadF32Matrix(InpRefDir + "x_stamp.bin", (ulong)L, 5, stamp))
|
||
|
|
{
|
||
|
|
Print("ABORT x_stamp");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
double ref[];
|
||
|
|
if(!LoadF32Flat(InpRefDir + "s2_logits_last.bin", L * V, ref))
|
||
|
|
{
|
||
|
|
Print("ABORT s2_logits_last");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- decode_s1 to obtain the context (and s1 logits for the pick)
|
||
|
|
CKronosPredictorS1 p1;
|
||
|
|
if(!p1.Init(KR_PRED_WEIGHT_DIR, KR_PRED_N_LAYERS, KR_PRED_D_MODEL, KR_PRED_N_HEADS, KR_PRED_FF_DIM))
|
||
|
|
{ Print("ABORT: p1 Init"); return; }
|
||
|
|
matrix s1_logits, context;
|
||
|
|
if(!p1.DecodeS1(s1, s2, stamp, s1_logits, context))
|
||
|
|
{
|
||
|
|
Print("ABORT: DecodeS1");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
//--- s1_pick = argmax of the LAST step's s1 logits (matches the reference)
|
||
|
|
int last = L - 1, pick = 0;
|
||
|
|
double best = s1_logits[last][0];
|
||
|
|
for(int j = 1; j < V; j++)
|
||
|
|
if(s1_logits[last][j] > best)
|
||
|
|
{
|
||
|
|
best = s1_logits[last][j];
|
||
|
|
pick = j;
|
||
|
|
}
|
||
|
|
PrintFormat("s1_pick (argmax last) = %d", pick);
|
||
|
|
|
||
|
|
//--- decode_s2 with the single picked s1, broadcast across context
|
||
|
|
CKronosPredictorS2 p2;
|
||
|
|
if(!p2.Init(KR_PRED_WEIGHT_DIR, KR_PRED_D_MODEL))
|
||
|
|
{
|
||
|
|
Print("ABORT: p2 Init");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Print("Predictor (s2) weights loaded.");
|
||
|
|
|
||
|
|
int pick_arr[];
|
||
|
|
ArrayResize(pick_arr, 1);
|
||
|
|
pick_arr[0] = pick;
|
||
|
|
matrix s2_logits;
|
||
|
|
if(!p2.DecodeS2(context, pick_arr, s2_logits))
|
||
|
|
{
|
||
|
|
Print("ABORT: DecodeS2");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
PrintFormat("s2_logits %I64u x %I64u", s2_logits.Rows(), s2_logits.Cols());
|
||
|
|
|
||
|
|
if(s2_logits.Rows() != (ulong)L || s2_logits.Cols() != (ulong)V)
|
||
|
|
{ Print("ABORT: s2 shape mismatch"); return; }
|
||
|
|
|
||
|
|
//--- full (256,1024) comparison; ref is row-major flattened
|
||
|
|
double maxerr = 0.0, sumerr = 0.0;
|
||
|
|
int wr = -1, wc = -1;
|
||
|
|
for(int i = 0; i < L; i++)
|
||
|
|
for(int j = 0; j < V; j++)
|
||
|
|
{
|
||
|
|
double e = MathAbs(s2_logits[i][j] - ref[i * V + j]);
|
||
|
|
sumerr += e;
|
||
|
|
if(e > maxerr)
|
||
|
|
{
|
||
|
|
maxerr = e;
|
||
|
|
wr = i;
|
||
|
|
wc = j;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
double meanerr = sumerr / (double)(L * V);
|
||
|
|
PrintFormat("s2 logits: max abs err = %.3e (row %d col %d), mean abs err = %.3e", maxerr, wr, wc, meanerr);
|
||
|
|
|
||
|
|
//--- argmax agreement on the LAST step (the row the AR loop samples)
|
||
|
|
int am = 0, ar = 0;
|
||
|
|
double bm = s2_logits[last][0], brf = ref[last * V + 0];
|
||
|
|
for(int j = 1; j < V; j++)
|
||
|
|
{
|
||
|
|
if(s2_logits[last][j] > bm)
|
||
|
|
{
|
||
|
|
bm = s2_logits[last][j];
|
||
|
|
am = j;
|
||
|
|
}
|
||
|
|
if(ref[last * V + j] > brf)
|
||
|
|
{
|
||
|
|
brf = ref[last * V + j];
|
||
|
|
ar = j;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
PrintFormat("last-step s2 argmax: mql=%d ref=%d %s", am, ar, (am == ar ? "(MATCH)" : "(DIFFER!)"));
|
||
|
|
|
||
|
|
if(maxerr <= InpTol && am == ar)
|
||
|
|
PrintFormat(">>> DECODE_S2 VERIFIED: max abs err %.3e <= tol %.3e, argmax matches. <<<", maxerr, InpTol);
|
||
|
|
else
|
||
|
|
Print(">>> DECODE_S2 MISMATCH: check cross-attn n_heads (4 not 8), non-causal "
|
||
|
|
"window, q-position broadcast, dep_layer RMSNorm, or proj_s2. <<<");
|
||
|
|
Print("================================================================");
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|