185 righe
6,5 KiB
MQL5
185 righe
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("================================================================");
|
||
|
|
}
|
||
|
|
//+------------------------------------------------------------------+
|