139 lines
5.4 KiB
MQL5
139 lines
5.4 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| KronosVerifyDecoder.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\KronosDecoder.mqh> // pulls in TokenizerMath + TransformerCore + loaders
|
|
|
|
//--- tokenizer config (config_tokenizer.json); decoder shares d_model/n_heads/ff_dim
|
|
#define KR_TOK_D_MODEL 256
|
|
#define KR_TOK_N_HEADS 4
|
|
#define KR_TOK_N_DEC_LAYERS 4 // BLOCKS = this - 1 = 3
|
|
#define KR_TOK_FF_DIM 512
|
|
#define KR_TOK_WEIGHT_DIR_D "kronos_weights\\tokenizer\\"
|
|
|
|
input string InpRefDir = "kronos_refs\\";
|
|
input int InpLookback = 256;
|
|
input double InpTol = 1e-4; // max-abs-error pass threshold
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| 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 (%u of %I64u)", fname, got, n); 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 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 (%u of %d)", fname, got, n); return false; }
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Script entry point. |
|
|
//+------------------------------------------------------------------+
|
|
void OnStart()
|
|
{
|
|
Print("================ Kronos decoder verification ================");
|
|
const int L = InpLookback;
|
|
|
|
//--- golden token ids
|
|
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;
|
|
}
|
|
|
|
//--- golden reconstruction (normalized)
|
|
matrix ref;
|
|
if(!LoadF32Matrix(InpRefDir + "recon_norm.bin", (ulong)L, KR_NFEAT, ref))
|
|
{ Print("ABORT: recon_norm.bin"); return; }
|
|
|
|
//--- build + load decoder, run it
|
|
CKronosDecoder dec;
|
|
if(!dec.Init(KR_TOK_WEIGHT_DIR_D, KR_TOK_N_DEC_LAYERS, KR_TOK_D_MODEL, KR_TOK_N_HEADS, KR_TOK_FF_DIM))
|
|
{ Print("ABORT: decoder Init failed (weights/paths)"); return; }
|
|
Print("Decoder weights loaded.");
|
|
|
|
matrix mine;
|
|
if(!dec.Decode(s1, s2, mine))
|
|
{ Print("ABORT: Decode() failed"); return; }
|
|
PrintFormat("Decode produced %I64u x %I64u", mine.Rows(), mine.Cols());
|
|
|
|
if(mine.Rows() != (ulong)L || mine.Cols() != KR_NFEAT)
|
|
{ Print("ABORT: output shape mismatch"); return; }
|
|
|
|
//--- float comparison: max-abs and mean-abs error, plus worst cell
|
|
double maxerr = 0.0, sumerr = 0.0;
|
|
int wr = -1, wc = -1;
|
|
for(int i = 0; i < L; i++)
|
|
for(int j = 0; j < KR_NFEAT; j++)
|
|
{
|
|
double e = MathAbs(mine[i][j] - ref[i][j]);
|
|
sumerr += e;
|
|
if(e > maxerr)
|
|
{
|
|
maxerr = e;
|
|
wr = i;
|
|
wc = j;
|
|
}
|
|
}
|
|
double meanerr = sumerr / (double)(L * KR_NFEAT);
|
|
|
|
PrintFormat("max abs error = %.3e (at row %d, col %d)", maxerr, wr, wc);
|
|
PrintFormat("mean abs error = %.3e", meanerr);
|
|
if(wr >= 0)
|
|
PrintFormat("worst cell: mql=%.8f ref=%.8f", mine[wr][wc], ref[wr][wc]);
|
|
|
|
//--- show first row side by side as a sanity glance
|
|
string a = "", b = "";
|
|
for(int j = 0; j < KR_NFEAT; j++)
|
|
{ a += StringFormat("%9.5f ", mine[0][j]); b += StringFormat("%9.5f ", ref[0][j]); }
|
|
PrintFormat("row0 mql: %s", a);
|
|
PrintFormat("row0 ref: %s", b);
|
|
|
|
if(maxerr <= InpTol)
|
|
PrintFormat(">>> DECODER VERIFIED: max abs error %.3e <= tol %.3e. <<<", maxerr, InpTol);
|
|
else
|
|
PrintFormat(">>> DECODER MISMATCH: max abs error %.3e > tol %.3e. "
|
|
"Check post_quant_embed shape, block count, or head transpose. <<<", maxerr, InpTol);
|
|
Print("=============================================================");
|
|
}
|
|
//+------------------------------------------------------------------+
|