From fe7268110d93e2abe4d4b51ac64e83521a8d6382 Mon Sep 17 00:00:00 2001 From: tslil Date: Sat, 19 Sep 2026 09:59:29 +0100 Subject: big refactor * use elo * optionally train on only diagonal * train-inference nonlinearity alignment --- include/weights_5.c | 550 +++++++++++++++++------------------ src/nn_train.py | 805 +++++++++++++++++++++++++++++----------------------- src/selfplay.c | 7 +- 3 files changed, 731 insertions(+), 631 deletions(-) diff --git a/include/weights_5.c b/include/weights_5.c index cbe5b53..93de126 100644 --- a/include/weights_5.c +++ b/include/weights_5.c @@ -1,297 +1,297 @@ /* generated by nn_train.py, do not edit by hand */ -/* iter=20, perf=+4837-2263=1700, rate=54.966 */ +/* iter=1, elo=1605.7, rated_games=1,200 */ #ifndef WEIGHTS_FIVE #define WEIGHTS_FIVE #include "weights_5.h" const float FIVE_embedding[7] = { - 0.0740088075, 1.24314356, 0.470590502, 1.9706943, -1.07658768, -0.110831268, -1.71863568 + -0.107056081, 1.57254577, -0.88146174, 0.129297495, 1.52432585, 1.08536971, 0.311268926 }; const float FIVE_dense_weights[FIVE_DENSE_NUM][FIVE_INP_NUM] NN_ALIGNED = { - {-0.736501038, 0.441505551, -0.0101214806, 0.00838176813, 0.128412887, 0.0572147146, 0.00972155482, 0.115386635, - 0.119603187, 0.14025943, 0.114817813, 0.0303258933, 0.0892734081, 0.11637944, -0.0400928557, 0.133098051, - 0.0543531738, 0.079443492, 0.137819752, 0.0814808607, 0.0843888149, 0.0232406333, 0.091927141, 0.0622601695, - 0.0152867809, 0.144588381, 0.129209518}, - {0.585523427, -0.348218173, 0.0201869905, -0.0927824378, -0.079847075, 0.00570499012, 0.019028658, -0.0525778793, - 0.0241511595, -0.0778653324, 0.0649214983, -0.0720155463, 0.0816128254, 0.152107835, 0.122573361, 0.00469767535, - 0.0939414054, -0.00473231031, 0.106732287, 0.0535288267, 0.121206462, 0.142429635, 0.0481809713, 0.0417780764, - -0.137944624, 0.0609199479, 0.137769178}, - {0.462448597, -0.407749623, 0.0928331017, 0.169065684, -0.0239023864, -0.043717999, 0.0748787001, -0.115180753, - 0.00713600824, -0.0456510931, -0.115847155, -0.0928038359, -0.0936625302, 0.00672320556, -0.122399807, -0.197665408, - -0.0889568478, -0.0234494805, 0.0380730927, 0.0320549458, -0.140820429, 0.123263285, 0.0330723673, -0.115847103, - 0.0344328955, 0.0078370925, 0.0235057231}, - {-0.394853741, 0.619607925, 0.000623293105, 0.0626177266, 0.0993065983, -0.0508532375, 0.0422961935, -0.0329102054, - 0.0658184364, -0.00211412669, 0.071218811, -0.00110832648, 0.0992975384, 0.0485603251, 0.043090459, 0.0198037624, - 0.144100145, 0.075020507, -0.0265296474, 0.1072428, 0.119981416, -0.081960164, -0.0284454729, 0.0727817416, - 0.0209743958, 0.017231239, 0.00270501012}, - {0.322544158, -0.334278047, -0.103440411, -0.166788399, -0.121835642, -0.0188177433, 0.0470861383, -0.0765447021, - -0.151401475, 0.0245341826, -0.0653189644, -0.137065485, -0.0791330934, -0.0928802639, -0.118125282, -0.0103837829, - -0.105004698, -0.124869317, -0.140310287, -0.0502006561, -0.154444039, -0.0629348978, -0.0932405964, -0.060754858, - -0.178571165, -0.0198839214, -0.0266791955}, - {0.48355487, -0.390889734, 0.077595599, -0.0655251518, 0.143206969, -0.102194585, -0.139597893, -0.0420332812, - 0.0287977494, -0.116232172, -0.0313235372, -0.0885956362, 0.033777222, 0.00323530566, 0.00361841219, 0.0489796698, - 0.162499145, -0.100385226, -0.160346776, -0.012796713, -0.092316702, 0.00321569922, 0.0583160706, -0.189311892, - -0.0899522752, -0.00434100768, -0.0259704161}, - {0.56332922, -0.362275988, 0.0443004631, 0.0566074625, 0.103790238, 0.116797395, 0.0716718212, -0.00739252847, - -0.0622435883, -0.0145862829, -0.0833693147, -0.136529267, 0.0718827471, 0.0215955507, 0.12628819, -0.0718128085, - 0.0909880102, -0.101973854, -0.00682962313, 0.0249344036, -0.0967680514, -0.0909264088, -0.166580185, 0.121361844, - 0.123275392, -0.0651039332, 0.0537181273}, - {-0.819170773, 0.319890618, 0.141533777, 0.129072368, -0.0416160114, 0.051628653, 0.081989117, 0.0895106494, - -0.0747076198, 0.1649829, -0.0243134368, 0.0412659608, 0.030081179, -0.0334956907, 0.00654935138, 0.149787158, - 0.0927348658, 0.0314128175, 0.130006343, -0.0245594271, 0.192781106, 0.0554638095, 0.0114317741, 0.178244412, - 0.132871851, 0.155762359, 0.0562597178}, - {-0.28783685, 0.800749838, 0.0654582605, 0.16760315, -0.0268351845, 0.0785852894, 0.0815776661, 0.0205644313, - -0.0319911316, 0.130168468, 0.0646079183, -0.0104910787, -0.0759830847, 0.0305559859, 0.16011776, 0.0711820126, - 0.0454082005, 0.078481257, 0.00481300708, 0.0328404978, 0.0453402773, 0.020932721, -0.0534755625, 0.0791933984, - 0.0573769771, -0.0207710471, -0.0651272088}, - {0.443260223, -0.382645726, 0.0540792719, -0.0148503678, 0.0803779736, -0.148579612, 0.175915852, 0.0861628428, - -0.126483589, -0.137266189, 0.0693714172, 0.0376117416, 0.0510658026, 0.0994918942, -0.00325085898, -0.141312346, - -0.18967995, -0.1160748, -0.0589719862, 0.0061827735, -0.127816349, -0.0692821294, 0.0541898757, -0.14229548, - -0.0578054674, -0.0225470457, 0.0464053452}, - {-0.204074055, 0.799709797, -0.0926644951, -0.0725759491, -0.0710309893, 0.084686704, 0.0408146083, 0.0254257284, - 0.121725418, 0.0215996467, -0.0359991416, 0.0957524031, 0.0953931063, -0.00680645928, -0.0204294901, 0.12974003, - 0.112353064, 0.156413019, 0.164305806, 0.0415933207, 0.0266439002, -0.0343691036, 0.0610345528, -0.0121211726, - 0.0274683293, -0.0188910402, -0.122497492}, - {-0.754237473, 0.489109159, -0.0150684342, 0.0150721166, 0.0898994058, 0.117045648, 0.180196047, 0.0989702791, - 0.118802801, 0.0894164145, 0.0476460047, 0.0852576643, 0.0704386756, 0.126215875, 0.0863139778, 0.0404747985, - 0.0579191074, -0.027498249, 0.0362317972, 0.0889331922, -0.0816930681, 0.0614292808, 0.0247090347, 0.136105731, - 0.157695234, -0.0156611446, 0.110241055}, - {0.313439459, -0.371197999, -0.0812235922, -0.130841494, -0.15772593, -0.0686921179, -0.113482796, -0.215832263, - -0.263810158, -0.138681024, -0.0457723662, -0.0189078543, -0.0898318738, -0.00338601694, -0.0972477868, -0.0171671677, - -0.175094023, -0.0579345673, -0.0215088259, -0.0257680323, 0.0197421573, -0.00804031081, -0.0486229621, -0.0935873836, - -0.0598373115, 0.0556947142, -0.0341284163}, - {-0.0283087846, 1.01821673, 0.0245439559, -0.0584667772, 0.0596237145, 0.117861398, -0.150972486, -0.105874307, - 0.13461031, 0.127710566, 0.0638094619, -0.0524306707, 0.0142664034, 0.176166981, 0.0509422906, 0.105261885, - -0.0829668492, 0.0342497528, -0.0993484035, -0.0566260181, 0.0703369901, -0.0444689468, 0.0637464449, 0.112646125, - 0.0266214907, -0.0401618667, -0.122857191}, - {0.494186699, -0.433338791, -0.0518285334, -0.124452204, 0.0497728549, -0.0852343068, 0.00520238606, 0.0706914961, - -0.00554902293, -0.0658616275, -0.0817680433, -0.119707204, -0.0898402631, -0.11220105, -0.0157136191, -0.104440816, - -0.00855437294, -0.116905071, 0.0119658746, -0.112882987, 0.0223040786, 0.0165890623, -0.0733309537, -0.10083314, - 0.0402964987, -0.0173071269, -0.115835465}, - {0.585159421, -0.537825108, -0.00638052402, -0.00731653441, -0.0890905112, 0.0726372227, -0.0513539203, -0.193280995, - -0.138472408, 0.00548683852, -0.0036317159, -0.0830583051, -0.251722008, 0.0221150201, -0.0875414535, -0.0016881146, - 0.108474821, -0.160211459, -0.115118034, 0.0284992438, 0.0648568422, -0.136975646, -0.122525007, 0.0966260657, - 0.0641387627, -0.113552749, -0.109446473}, - {0.193843648, -0.242976606, -0.193332702, -0.292165011, -0.278867573, -0.228950977, -0.238747001, -0.0930175334, - -0.0573855378, -0.165438771, -0.240651086, -0.0511921868, 0.0324299969, -0.0392116196, -0.111929521, -0.274590582, - -0.148756132, -0.111382566, -0.0805970877, -0.0647319108, -0.199062288, -0.185016915, 0.0627402514, 0.00906337332, - -0.0627135858, -0.135310128, -0.169047281}, - {-0.215394437, 0.889513314, 0.00638777902, 0.00826172903, 0.0156073878, 0.0459904447, -0.00762421312, -0.0168544892, - 0.0577065274, 0.0580772273, 0.0874491185, -0.0387069285, 0.0537195019, 0.10909301, 0.10909342, 0.0418900773, - -0.0534538031, -0.0679726452, 0.113790199, 0.058318954, -0.0312984921, -0.0566174537, -0.0532646477, -0.0796468034, - -0.124961801, -0.00909277145, 0.0655762851}, - {-0.228752688, 0.836602569, -0.066971913, 0.00661093649, 0.0622722507, -0.0991612822, 0.0580747649, 0.0461828969, - -0.00459896866, 0.0183859095, 0.125690386, 0.0345075168, 0.055562906, 0.0219121948, 0.0377271026, 0.0509790927, - 0.116534844, 0.0217704326, 0.0595090501, 0.0035141164, -0.0847472772, 0.0247160643, -0.0256635621, 0.105417542, - -0.0172405094, -0.00555314263, 0.0275831074}, - {-0.523936927, 0.542215705, 0.0836628824, 0.0148690064, -0.107132636, 0.0131806992, 0.0877602249, 0.0387383178, - 0.0478802584, 0.0926990509, 0.191303402, 0.106592536, -0.0540394038, 0.0751547292, -0.0609236471, -0.0316190124, - -0.0191638581, -0.00913275406, 0.0661239922, 0.183413312, -0.0261334088, 0.0737154484, 0.0801930279, -0.0199935101, - 0.0367107987, 0.0859389529, -0.0555933639}, - {0.288705468, -0.441975057, -0.10542386, -0.027804669, 0.0127640441, -0.188249782, -0.0386438929, -0.159199029, - -0.115368813, -0.109920412, -0.0792587996, -0.128983915, -0.174695253, -0.15355587, 0.013300905, -0.131267965, - -0.196564063, -0.13494356, -0.176885277, -0.0716164261, -0.0909028128, -0.172184154, -0.173392311, -0.061146494, - -0.0728916377, -0.0879944786, -0.130929112}, - {0.577622175, -0.508731306, 0.0489397533, -0.0387292616, -0.175800875, 0.0470782071, -0.0244599395, -0.183845922, - -0.076273866, -0.0991943106, -0.172568753, -0.0689993054, -0.0389560014, -0.089046672, 0.0276372749, 0.039563179, - -0.0502255633, 0.0743123293, 0.0455570854, -0.176738515, -0.0365099125, -0.105101839, 0.0263801813, 0.0622431785, - -0.00551946554, -0.176056966, -0.149150908}, - {0.336864412, -0.319015056, 0.132177919, 0.00744339731, -0.211662367, 0.0252622422, 0.0705826059, 0.0777326003, - -0.156707972, -0.0793115273, 0.0194405708, -0.0405637026, -0.12632072, -0.189731076, -0.0813506842, -0.094583191, - -0.0984284878, 0.034173172, -0.113607906, -0.0468458906, -0.107121952, -0.0256407987, -0.022450408, -0.243887752, - -0.0653076544, -0.0913802236, -0.10388568}, - {0.578416288, -0.503526211, 0.0678627491, -0.0796723217, -0.0205171332, -0.087524496, 0.123584375, -0.0171893202, - 0.0144450143, 0.0352460146, 0.0494950749, 0.0144806793, -0.122311831, 0.104767658, -0.0340576917, -0.0769768059, - -0.187032133, -0.0312526077, 0.0730399415, -0.0127690043, -0.0796863586, -0.0862771943, 0.00205425057, -0.0247630179, - -0.0599246062, -0.100494251, -0.00546842441}, - {0.562040985, -0.488121718, -0.0126014715, 0.0654413924, -0.0157233886, -0.0506547168, -0.0735116154, 0.000446558377, - 0.0883243307, 0.0476379693, -0.0356399193, -0.0790520981, 0.0242921375, 0.083447054, -0.0226964466, -0.0555270053, - -0.0491245911, -0.11149352, -0.0803522915, -0.129119724, -0.121286027, -0.0180314351, -0.00345550943, 0.119797938, - 0.00104405289, -0.101297848, -0.0751108006}, - {0.238196939, -0.53691113, -0.151438579, -0.100090817, -0.176935419, -0.0520765968, -0.266078323, -0.0999380946, - 0.040820688, -0.0347121321, -0.0450287312, -0.183185175, -0.163738295, 0.000619773462, -0.0867412314, -0.0491779186, - -0.236263737, -0.157642022, -0.0430997536, -0.14331156, -0.118139446, -0.16108115, -0.201048821, -0.177758396, - -0.129035383, -0.203504562, -0.164767295}, - {0.441368878, -0.395885527, -0.153076977, -0.0806180239, -0.0695551485, -0.0865602046, -0.211709112, -0.0284602828, - -0.127726078, -0.00846482534, -0.164641082, -0.104029126, -0.21861203, -0.167878583, 0.00975916069, -0.0954109281, - 0.000394121686, -0.102626011, -0.019367246, -0.114014499, -0.0390974656, 0.0309991166, 0.0340251587, 0.0921528116, - -0.133139834, 0.110572889, -0.0450299494}, - {-1.37051094, -0.209623411, 0.138460785, 0.092090182, 0.0507118851, 0.0916386992, 0.188570067, 0.0877156034, - 0.00925927609, 0.0311223976, 0.158533677, 0.0935553014, 0.0593449324, 0.0900341645, -0.0495540574, 0.0888268873, - 0.00726486882, 0.195680708, 0.00532209128, 0.121221334, 0.0602692068, 0.0463516042, 0.0633608252, 0.000764071126, - 0.142929018, -0.0125963408, 0.140731975}, - {-1.02481186, -0.0301061235, 0.0968682766, -0.00556900632, 0.131804481, 0.076072745, 0.0394872352, 0.124811731, - 0.0580817759, -0.0613573231, 0.137282491, 0.0988281816, 0.110931978, 0.0479087867, 0.0885298625, -0.0936895385, - 0.173342228, -0.0392186679, 0.102072865, -0.0210707225, 0.102531731, 0.152089283, 0.0219103396, -0.0106732855, - 0.0755668655, 0.107699119, -0.037840154}, - {-0.440617263, 0.427588522, 0.0922426656, 0.149832055, 0.141998261, 0.0473250188, -0.0015713285, 0.0251766704, - 0.175777137, 0.0605928078, 0.14569357, -0.040041931, -0.0712837875, -0.0216561873, 0.155275241, 0.0395933017, - -0.0587713532, 0.0714753345, 0.169354916, -0.0907185599, 0.121233217, 0.102245063, -0.076196596, -0.073741734, - 0.117569886, -0.00979469996, 0.066190891}, - {0.0369343646, 0.94740963, -0.120297633, -0.0240263045, -0.0747312531, -0.0370690227, -0.0871979296, 0.0721855164, - -0.0477090999, -0.0303094052, -0.0174251776, 0.0737490803, -0.0174532924, 0.202143535, 0.044087287, 0.136250496, - 0.0836504027, 0.0106535666, 0.0564865582, 0.143943682, -0.0540259853, 0.14196521, -0.0470602587, -0.0595160872, - -0.067465283, -0.0373986252, -0.122069307}, - {0.536459267, -0.527057171, 0.0432944037, -0.0220577996, 0.0586258806, 0.0299046487, -0.03634426, -0.134697944, - 0.0617770702, 0.0597911552, 0.0829500481, 0.0790654123, -0.0937644318, -0.138984412, -0.0958245695, -0.136554793, - -0.149459213, -0.00758869108, -0.0619160868, -0.0150070162, -0.12118274, -0.0870625973, -0.0453385152, -0.0505067669, - 0.0766466856, 0.081386447, -0.0441951305}, - {-1.5428828, -0.80797714, 0.0740097687, 0.0697444305, 0.057266742, 0.122709066, 0.0515730716, 0.0172563121, - 0.102879532, 0.00833038613, -0.0306954794, 0.0508712716, 0.0623149313, -0.0547058731, 0.0178796276, 0.0469872989, - 0.048006475, 0.138395235, -0.015775077, -0.0874862075, -0.0236810762, 0.192813948, 0.102375232, 0.182756573, - 0.0315079354, 0.17786096, 0.120102532}, - {0.404215246, -0.463934869, -0.0957639143, -0.153242469, -0.129122972, -0.0429926887, -0.00734173926, -0.130690306, - -0.0292293392, -0.101523019, -0.0187744685, -0.0789348856, -0.028868366, 0.0663219988, -0.12293189, 0.133115426, - -0.0129556032, 0.0705926567, -0.00292059872, 0.106569223, 0.068127282, 0.0237778127, 0.154400885, -0.203437477, - 0.0205398705, -0.100581557, -0.120557994}, - {-0.644988537, 0.49214381, 0.150650322, 0.112618349, 0.118532732, -0.0712057278, 0.109975316, 0.0600802526, - 0.11721167, 0.0043891496, 0.0445214249, 0.020120509, 0.0575481392, 0.0311500095, 0.070253849, 0.0899710879, - 0.00519787194, 0.139914215, 0.00923856813, 0.073828876, 0.0130092464, 0.135768488, 0.135616556, -0.0155476285, - 0.0110093774, 0.141182959, 0.0469711907}, - {0.565220535, -0.45870927, -0.0676563606, -0.103016622, 0.0210752469, 0.11313884, -0.141023487, -0.0987690315, - -0.00595930219, -0.00645625824, -0.145734802, -0.143644974, 0.0660507381, -0.0887921229, 0.103647389, -0.10528554, - -0.117506079, -0.0474755652, -0.110127009, -0.0812641829, 0.00495389896, -0.127982289, 0.00333370781, -0.161127314, - -0.132345542, 0.026314592, 0.0338136926}, - {0.425351769, -0.419588655, 0.0911391899, 0.0296612848, -0.158307016, -0.183616206, -0.0537261553, 0.151801199, - -0.070437476, -0.144536048, 0.0424512364, -0.097841166, -0.00756636076, -0.0642707944, -0.0151114604, 0.0219121445, - -0.115748204, -0.112595864, 0.0332745798, 0.030156292, -0.0302893762, -0.168612301, -0.025304215, -0.0259683151, - 0.0275830887, -0.113976859, -0.103646033}, - {0.635811269, -0.484070182, 0.0425479375, -0.0276354123, -0.0907608867, -0.0059059551, -0.0439028107, -0.000382573809, - 0.0340211354, 0.0319638103, -0.0113164345, -0.0539076701, -0.0457570031, -0.00216524722, -0.0475030392, 0.00518768514, - 0.0944753811, 0.017696023, 0.101162143, -0.0821021795, -0.0974972546, -0.0857279897, -0.0456408188, 0.0471956506, - -0.189597234, 0.0393579602, 0.0866887048}, - {-0.499247909, 0.543323755, 0.0900440738, -0.056884367, 0.0500761643, 0.00318569271, -0.0280284118, -0.110797897, - 0.17162694, -0.0145060718, 0.0115644, 0.00268066581, -0.00221528695, 0.0504573807, 0.137124568, -0.0380336717, - -0.0434476212, -0.0169732086, 0.165596545, 0.0667509511, 0.138989732, 0.0213365871, -0.0366825201, 0.0830830038, - -0.00564401317, 0.0655842274, 0.0633930266}, - {0.70726335, -0.293301582, -0.0149804838, -0.0407507345, 0.0592219196, 0.142761424, -0.058007393, 0.0426381007, - -0.0269866847, 0.086824134, 0.0405586213, -0.0860687941, 0.0596791469, -0.0316971801, -0.0820193738, 0.094117634, - -0.10543634, 0.140936255, -0.145996511, -0.104174055, 0.121777564, 0.0991584435, 0.0770189837, 0.12082129, - 0.122225203, 0.0808218941, 0.0609109141}, - {-0.64608264, 0.476182133, 0.11432562, 0.143952027, 0.102427512, 0.108211726, 0.0424858816, -0.00217763684, - 0.0933892354, 0.0845816955, -0.0416734777, 0.0165807977, 0.0763965845, 0.0119573381, 0.10007228, 0.134320587, - 0.192003861, 0.0674655959, -0.043181546, 0.0899695978, 0.0556872673, 0.104730159, 0.0565740578, 0.113215894, - 0.127959728, 0.0764361992, 0.0625143424}, - {0.508454621, -0.388237149, 0.0380777717, 0.09970662, -0.0212344527, -0.111735195, -0.127914205, 0.0887548178, - -0.185714722, 0.0326851979, -0.0785226375, -0.137000754, 0.0644617528, 0.0518359952, 0.00604667002, -0.0273073856, - 0.015539689, 0.0862407684, -0.120538272, 0.015681047, -0.116713345, -0.0603444837, 0.0632756948, -0.0189401153, - -0.103490613, -0.0350942872, -0.11512392}, - {0.456700772, -0.404712647, 0.06749513, -0.064227134, -0.0689638332, -0.0506657399, -0.142596498, -0.139065787, - -0.12147744, -0.183219835, -0.0241773743, -0.00420871517, 0.0546985529, -0.0776123032, -0.177308828, -0.199897021, - -0.153310016, -0.154843956, -0.0349417962, -0.154218048, 0.0284505915, -0.00227548159, -0.082287766, -0.0456741937, - -0.0863075778, 0.0297212899, -0.0931005254}, - {0.305552572, -0.315883875, -0.122184627, -0.0746651217, 0.0342479385, -0.0904350281, -0.245500386, -0.028839428, - -0.0701977536, -0.135232389, -0.165449649, -0.201628625, -0.0494867563, -0.109070107, -0.188339859, 0.0062798541, - 0.0606066026, -0.00351285841, -0.0736040324, -0.0990265533, -0.0258480106, -0.120790169, -0.0687542558, 0.0293561108, - -0.108199641, 0.049893599, -0.12316478}, - {0.29987666, -0.572770119, -0.214782536, -0.0542312413, -0.108061738, -0.101396576, -0.0827371478, -0.0851614699, - -0.00562301371, -0.152533382, -0.0901153535, -0.100591116, -0.128925681, -0.0542940423, 0.0350219384, -0.0491921976, - 0.00431972975, -0.130837634, -0.0822021365, -0.0177699849, -0.185890228, -0.0105574373, -0.202068493, -0.117978066, - -0.220640764, -0.0570592247, -0.292594552}, - {0.494745016, -0.417134374, -0.134922132, -0.0530528873, 0.0185136888, -0.0505652055, 0.0923090801, -0.0213337392, - 0.0254124161, -0.0483726412, -0.0614903308, 0.0912698284, 0.00118646806, 0.000871023745, -0.123800509, -0.0349011831, - -0.0204420723, 0.0510278866, -0.108978763, -0.0903524011, -0.11572279, 0.00258875033, -0.11578048, 0.0649974346, - -0.233644098, -0.143126875, 0.0714745894}, - {-0.466099918, 0.303083658, 0.194454432, 0.0330169648, 0.0536028706, -0.0497129075, 0.0966591984, -0.124805987, - -0.082423687, -0.0515044816, 0.0231322292, 0.130053014, -0.109944403, 0.144403294, -0.0845312849, 0.0685306564, - 0.0952532962, 0.00103461824, -0.0119229294, 0.0040881224, 0.140647337, -0.000325238216, 0.000757269212, 0.0427705832, - 0.155582026, -0.00478899945, -0.0782169774}, - {-0.579050004, 0.456353992, 0.0295837484, 0.0810229331, 0.110328488, 0.0420724191, 0.050499171, 0.134771183, - -0.0625161082, -0.0464896485, -0.0148950368, -0.0247010048, 0.0452727154, -0.0598820895, 0.193118423, -0.00318598771, - -0.00731150666, 0.0971256569, 0.0108000766, 0.160293519, 0.0459034592, 0.00420842972, 0.134508863, 0.0377153382, - 0.0310785193, 0.116767183, -0.0212338604}, - {0.492659539, -0.440205097, -0.1786699, -0.14724575, -0.146198928, 0.0497965477, 0.0124387546, 0.100123711, - -0.123940602, -0.0283736996, 0.0403211005, 0.147481978, 0.0415745042, 0.00405436335, -0.150250316, 0.0711188614, - -0.000899086765, -0.116314314, -0.0729056522, -0.0609736517, -0.150646538, -0.0844909176, -0.0804084763, -0.0814922377, - -0.00574966893, -0.0615304783, -0.130495623}, - {0.375148445, -0.35052672, -0.21811676, -0.111509539, -0.111186869, -0.0975456983, 0.0201611463, 0.0519107096, - -0.0776508376, -0.211821184, 0.0204374492, -0.160981134, -0.0669252574, -0.11746414, -0.119440816, -0.110870838, - -0.0161191821, 0.147800952, -0.0731140003, 0.0409589112, -0.152980223, -0.0631486773, 0.024988275, -0.0637564436, - 0.05677123, -0.151989713, 0.146640077}, - {-0.537738979, 0.155770138, 0.0717488229, 0.154025748, -0.0575252771, 0.178430438, -0.0433261469, 0.0817758739, - -0.037413165, 0.115568593, -0.016169101, 0.059824802, 0.0719826445, 0.0910876915, 0.0896192044, -0.0639773533, - 0.0665314645, 0.0056780125, -0.0497693233, 0.0644020513, 0.0495124944, -0.0795804262, 0.00850042328, 0.126630023, - -0.108872443, 0.047845453, 0.118190601}, - {0.397517473, -0.496414095, -0.134717777, -0.121990517, -0.0415601805, -0.15664281, -0.142036721, -0.103453189, - -0.087386325, 0.0575556234, 0.0110460855, -0.0624599159, -0.0119338734, -0.0386830419, -0.0431415178, -0.0480975658, - 0.0445168614, 0.017456213, -0.00431484589, 0.0308391713, 0.00833894685, -0.0886696875, -0.183318466, -0.121195629, - -0.0626910776, -0.109209515, -0.175251946}, - {0.443285644, -0.376179397, -0.0270347875, 0.135097116, -0.0652561337, 0.0533783548, -0.014442821, 0.0201152023, - 0.00358327036, -0.0973063484, -0.171811253, 0.0935230479, -0.0994925722, -0.0457014367, -0.0259426255, -0.0118914824, - 0.00667368574, 0.00211936398, -0.12007203, 0.112607278, 0.0472122319, -0.00623246795, 0.107382551, -0.137344256, - -0.0901683196, -0.114172265, -0.0637115687}, - {0.481253833, -0.459548533, -0.00186790479, -0.0670129359, 0.0119494796, -0.132754967, -0.100173682, 0.00466447277, - -0.178400099, -0.118565761, -0.143831864, -0.0246553589, -0.102533117, -0.107857428, -0.120118216, -0.100659706, - -0.0394478105, -0.0107691484, 0.0909453034, -0.0510972999, -0.0987442434, 0.0210721195, -0.135219529, -0.136416972, - 0.0104762809, -0.0321881138, -0.080034934}, - {0.478051156, -0.390066892, -0.0616386048, -0.0139461271, -0.12503244, -0.0886834487, 0.0696618259, -0.122561499, - -0.127830952, -0.135499537, -0.0724472106, 0.0503810309, -0.0329925232, -0.121970139, -0.0805257484, -0.0517395064, - 0.127011746, -0.105815455, -0.117574736, -0.171412915, 0.00718646124, -0.0142810643, -0.108239599, -0.113955647, - -0.115745522, -0.186678171, 0.0428371988}, - {0.500688553, -0.457732707, 0.0468688384, -0.0812474936, 0.0559192821, 0.0192655697, -0.00432712026, -0.0348228589, - 0.0680508986, -0.0765108988, 0.0665702373, 0.0890227407, 0.110584609, 0.0915147886, 0.00808657613, 0.0324192569, - 0.152577803, 0.0244663972, -0.133136615, -0.0185757652, -0.179004312, 0.114306241, -0.0481279902, -0.0929322466, - 0.0698894933, -0.154856935, -0.0797469243}, - {-1.10205662, 0.0431513935, 0.0359299965, 0.0410667099, -0.0479542539, 0.0948511511, 0.12424472, 0.0309509933, - 0.0864339918, 0.029587606, 0.0145721287, 0.0853804871, 0.132514894, 0.106967807, 0.0772302672, 0.114916787, - 0.125742197, -0.00166881434, 0.0482046753, -0.00177590875, 0.137009561, 0.0597598515, 0.178690583, 0.0321583077, - 0.0264418647, -0.0577933304, 0.143539712}, - {-0.169617161, 0.753173649, -0.0357469134, -0.143619597, -0.0365971848, 0.0783468112, -0.00600597309, -0.0300697405, - 0.0504271351, 0.129783496, 0.0770770609, 0.133545205, 0.0330213122, -0.00300192437, 0.021057032, -0.0731424466, - -0.0704107434, 0.153760269, 0.122179128, -0.0806687102, 0.0635517538, -0.0575274974, -0.000880315551, 0.0180198345, - 0.0463861525, 0.0521901958, 0.114362903}, - {0.541069031, -0.373762012, -0.00346784736, -0.114745341, 0.0749837831, 0.023730997, 0.119919084, 0.0436235741, - 0.0766937137, -0.0944101363, 0.0768890977, 0.0154710021, -0.0146260886, -0.0396183915, -0.15101184, -0.103892073, - 0.032796409, 0.01677504, -0.0131742777, -0.122963153, 0.0478341803, -0.0416218005, 0.0621234663, -0.0900596976, - -0.095683597, 0.0570060574, -0.148392186}, - {0.621991098, -0.412671417, 0.109054297, 0.152968824, -0.109320141, -0.0486302823, 0.105001248, -0.0630277395, - 0.0720740482, 0.00874471292, -0.118035778, -0.0964144766, -0.0285033491, -0.118909054, -0.134643853, 0.138064712, - -0.0398782529, 0.119126923, -0.148600459, -0.07180015, -0.00132761989, -0.0327637903, 0.0603960119, 0.110346965, - 0.0160790533, 0.0838280022, 0.0681004152}, - {0.267255366, -0.300656796, -0.308595836, 0.0114773903, -0.00455049379, -0.188414246, -0.000839192071, -0.160705596, - -0.0327411033, 0.0353504717, -0.148212522, 0.0458654165, 0.0401847027, 0.00880304165, -0.00134926476, 0.151421279, - 0.0980324224, -0.155263439, 0.0947797149, -0.0275884662, -0.010804561, -0.0862751678, -0.0493875332, -0.16067642, - 0.0359508097, -0.0833133236, 0.0724551156}, - {-0.579416513, 0.183669999, 0.156003579, 0.0300249904, 0.0622566901, -0.0566965528, -0.0361310914, 0.0524020791, - -0.030924283, -0.0140644573, 0.027700752, 0.101386458, 0.0708734393, 0.0798268691, 0.0485159382, -0.0826731846, - -0.0398858935, -0.121528007, 0.160635203, 0.0963176936, 0.00677957386, 0.0833255649, 0.0618095621, -0.0827444941, - 0.160995021, 0.103194773, 0.0617046356}, - {0.676655293, -0.388367414, 0.0809247419, 0.0668345466, -0.171927795, 0.0357040837, 0.0894320607, 0.0448640287, - 0.0496236421, 0.0481129847, -0.0973136052, 0.161646038, -0.113477305, 0.04949544, 0.0729649812, -0.0361371897, - 0.0662086233, -0.00700450502, -0.116499677, -0.0211075936, 0.070632197, 0.0159394443, -0.0889575556, -0.0802729949, - 0.0583706349, 0.068704322, 0.0971004963}, - {-0.851525426, 0.0957234949, 0.052559007, 0.0460673496, 0.0693054795, 0.0644561276, 0.11398416, 0.021627564, - 0.0437199362, 0.103789032, -0.0312068891, -0.0665286854, 0.0249293167, 0.0493387133, 0.0870543793, -0.0129110338, - 0.193294987, 0.15596509, 0.00858440436, 0.0967156887, -0.0302792024, 0.0566488765, 0.0778378099, -0.0519785471, - -0.0802783072, 0.109945856, 0.093652375}, + {-0.12155433, 0.0380854495, -0.0526241288, -0.122302413, -0.182421431, -0.0367297009, 0.130855337, 0.00196790509, + -0.0147297382, -0.028007213, 0.000209137797, -0.0078575341, 0.137054384, 0.122178458, -0.0867310241, 0.0745834112, + -0.0554108731, 0.00852537062, -0.124409162, -0.183914825, 0.17473805, -0.0252411161, -0.181904465, -0.0686189234, + -0.0576762632, -0.0431368724, 0.0593770556}, + {0.126471147, 0.0102750072, 0.176142693, -0.0824196339, 0.0451394655, -0.165960342, -0.0628453344, -0.0960823447, + 0.0318342112, 0.000965576095, -0.00438163895, 0.0193198957, -0.0445231795, -0.151376769, 0.0875950605, -0.0467983, + 0.178420976, -0.116750538, 0.0425412133, 0.101727553, -0.0950874984, 0.124374248, -0.0662044585, -0.0384465531, + 0.143683732, -0.0826372579, -0.129666358}, + {0.00145194307, -0.182082057, 0.0898404941, -0.189079747, 0.126428112, -0.118196607, -0.00724528497, -0.0462002754, + -0.123565383, 0.0588053241, 0.0816431642, -0.162116483, -0.167529151, -0.191269279, -0.117242776, -0.0594705231, + 0.159989774, 0.189793959, -0.0976364538, -0.14519015, 0.025564136, 0.150649741, -0.188298583, 0.173989639, + 0.13177675, -0.0306688342, -0.0326667689}, + {-0.0356031395, 0.177603677, 0.129797876, -0.128613308, 0.123220339, 0.183339179, -0.0595809631, 0.0203314237, + -0.0285057854, 0.099734731, -0.130372807, 0.041145131, -0.00959177595, -0.0443884656, -0.112532496, 0.0752916262, + 0.159095958, -0.187638044, 0.153513178, -0.179985285, 0.0458669513, -0.149700686, -0.186654389, -0.111326285, + -0.176224634, 0.0779583603, -0.0512998775}, + {-0.137284145, 0.0506111868, -0.113694407, 0.110263176, -0.0403873399, -0.0899731219, -0.147952154, -0.121726736, + 0.0471870489, -0.132552579, -0.16430828, 0.144172087, -0.114312761, -0.114386886, -0.0749448165, -0.186088592, + -0.0914313719, 0.0271352176, -0.0279148035, -0.0927195996, 0.153074369, 0.0348081589, 0.0822597742, 0.0405591056, + 0.0267426129, 0.00375819439, 0.176896647}, + {0.074619934, -0.164365172, 0.191026345, -0.102066979, -0.132967383, 0.0662865639, 0.0961742327, 0.154202238, + 0.0644698441, -0.144472241, 0.0493853837, 0.0597836785, 0.166797876, -0.0320083834, 0.0830717087, 0.0783591345, + -0.0477294624, 0.133098975, 0.00170811161, 0.140096471, 0.050632339, -0.149140581, -0.0281639751, -0.0486545451, + 0.0689834952, 0.173242837, -0.163674608}, + {-0.101129092, 0.0826225281, 0.123690508, -0.147909224, -0.0644332319, -0.137339801, 0.0642950758, 0.048136957, + -0.119815819, 0.177866101, -0.0335282795, -0.125992149, -0.176234365, 0.0665554702, 0.0907775313, -0.0200865213, + -0.0853773206, 0.124072194, 0.088058278, 0.0937990397, 0.159939021, 0.0153142968, 0.0101294639, -0.113451913, + 0.0883233249, 0.107491463, 0.0322958007}, + {-0.0780490264, 0.0602351725, -0.0143457381, 0.0149356192, 0.0878894702, 0.0939516276, 0.0259169601, -0.00715420581, + -0.154600754, 0.0687108785, -0.0510659851, 0.0573821962, -0.133331433, -0.0619913489, 0.15025425, 0.12487828, + -0.175620094, 0.149448395, -0.0759175718, 0.103955485, -0.126907349, -0.185391665, -0.184962243, 0.068593502, + 0.0869200453, -0.136647373, 0.0553372279}, + {0.134603456, 0.100999378, -0.0795233175, -0.0963680223, 0.102558665, -0.0179742426, 0.0742983818, -0.106091365, + 0.0150560867, 0.000919669459, -0.0256554, -0.0586289912, -0.0616930351, 0.0811018348, 0.00295353238, -0.013059183, + 0.115540653, 0.138279736, -0.0924114212, 0.0318339355, 0.175884411, -0.185929313, -0.0538378656, -0.0973959491, + -0.102074087, -0.073292248, 0.0162393115}, + {-0.0503677502, -0.0935814828, -0.0912126452, -0.135719061, -0.0878928229, -0.0450617634, 0.0294947159, 0.147923633, + 0.0176191255, -0.110445336, -0.0291322805, -0.0655989721, 0.10651508, -0.154051855, 0.143873185, 0.127390936, + -0.0714856684, -0.12482097, -0.0285283364, 0.135305271, -0.0861330926, 0.147342265, -0.0150353471, 0.109596536, + -0.163149804, 0.0803325251, -0.0306352694}, + {-0.0495440029, -0.185366139, 0.0192145016, -0.190048054, -0.101420864, 0.0903542489, 0.160431951, -0.149787381, + -0.0645608827, 0.0384876654, 0.123749927, 0.168721348, 0.109497309, -0.106394224, -0.136118546, -0.0157899503, + -0.00072363147, -0.13675034, -0.0100835115, 0.180498168, 0.0426577106, -0.0640986487, -0.0987099707, -0.162526459, + -0.157510012, -0.13352868, 0.161013126}, + {-0.12659438, 0.0168235712, 0.0670667961, 0.115326628, -0.0299799368, 0.140033036, 0.150276676, -0.167988017, + -0.0454494804, -0.0861340985, -0.0992069095, -0.175068781, -0.143283069, 0.00551927881, 0.014438469, -0.089709267, + 0.0134409117, 0.14857167, -0.0528969057, 0.174673587, -0.144731894, 0.033209689, 0.0673518255, 0.0152981915, + 0.0599667318, 0.108046263, -0.00661131041}, + {0.0865569413, 0.0201035198, -0.0276535638, -0.15255779, -0.0266870484, 0.00874882471, 0.105382077, -0.0825635046, + 0.00467901072, -0.0188698228, -0.0421445034, 0.140830904, 0.173780039, 0.0673350543, -0.0174199212, -0.178080082, + -0.168101251, -0.14888671, -0.101302899, 0.148781419, 0.178234026, -0.0785033926, -0.0177648757, 0.0779984891, + -0.0615693107, -0.0639129579, 0.135591194}, + {-0.138985217, -0.136894986, -0.0396100953, 0.0743817091, 0.144577697, -0.105559923, -0.111216575, -0.0496893153, + -0.0599366538, 0.000612799427, -0.0092763491, 0.182437062, 0.0282868054, -0.043189019, 0.109706245, 0.165155888, + -0.127432227, -0.106511891, -0.172343493, 0.101189204, 0.0647119284, 0.121372372, 0.100672714, 0.125937566, + -0.141099468, -0.033982072, -0.0187687632}, + {0.00770451175, 0.00267756497, -0.123039216, -0.109877437, -0.0682492852, 0.0418347865, -0.167821661, -0.013173731, + -0.0488652214, -0.108915366, 0.0675020665, -0.0615673847, -0.0424148478, 0.00257005938, -0.00371407717, -0.174944207, + -0.00558308, 0.015326662, 0.162353009, -0.0655369163, -0.169667333, 0.0822051764, -0.10064137, 0.125505, + 0.0271434523, 0.137520015, 0.163881466}, + {-0.149971426, 0.189632416, -0.126153424, 0.0586789139, 0.0396591425, -0.0692966059, 0.107502334, 0.0817965791, + -0.112501733, 0.0323353969, -0.15788129, 0.152778834, -0.115438104, 0.188251644, -0.0657786801, 0.189103797, + -0.0885873437, -0.18719843, -0.154167324, 0.0615214072, -0.16028747, 0.120422281, -0.146504149, -0.130510226, + -0.0206950977, 0.109188057, -0.11423634}, + {0.154549837, 0.0535175726, -0.00212893379, 0.151742667, -0.0805903003, 0.0289018992, 0.0434413366, -0.117259227, + 0.0653587058, -0.171512067, -0.0490244366, 0.0232665353, 0.163909137, 0.0886328816, -0.184273347, 0.0722340047, + 0.0775859952, -0.063730754, -0.171883166, -0.0819482282, 0.112369493, -0.102479242, -0.134144306, -0.149879813, + 0.127042294, -0.1197583, -0.0607419573}, + {0.160955414, -0.181970119, 0.0130247241, -0.137568071, 0.111093856, -0.000298083323, -0.0164680183, -0.132458195, + 0.0903752446, 0.0993224457, 0.144108832, 0.189305916, 0.0579277538, -0.0724364668, -0.15050526, 0.16396369, + 0.0679968074, -0.149189174, 0.0887536258, -0.0155692035, 0.069320716, 0.109476641, -0.137493536, -0.179973945, + -0.0464075767, 0.177120373, 0.0882390365}, + {-0.188345999, 0.125080094, -0.0543377437, 0.121041141, 0.105408385, -0.0432622507, 0.0292727314, -0.0274563339, + 0.0337398723, 0.0579176582, 0.0713827536, 0.0547062382, 0.113494053, -0.00798128173, -0.0870676488, -0.0703901947, + -0.0123118069, -0.148690388, 0.032527443, -0.0525818206, 0.0352050774, -0.0718326196, -0.100015223, -0.0681334734, + 0.0145522375, 0.0416409969, -0.126224935}, + {0.0947042331, 0.103619061, -0.125910088, 0.0281794611, 0.11256893, 0.0279837437, 0.0589137003, -0.0308914613, + 0.108718254, 0.0485800542, -0.18296133, 0.115607113, -0.115321189, 0.0935213491, -0.156311691, -0.141139984, + -0.120314941, -0.129003659, 0.0151534975, 0.0197912827, -0.126248688, -0.0518530272, 0.00858066045, -0.122916773, + -0.00603546994, -0.0202781074, -0.00830999296}, + {0.126908973, 0.103868783, 0.1511406, -0.152139083, -0.099162519, 0.162759542, 0.113781497, -0.110512532, + 0.0229097195, -0.0788602754, 0.152314857, 0.181817308, 0.154285446, 0.0671618208, -0.0169426389, -0.178109497, + -0.0274765678, -0.168348387, -0.122650579, -0.0837040991, 0.158916831, -0.175366521, 0.0213023461, -0.130665213, + -0.00817442965, 0.154927447, -0.11668735}, + {-0.00094421726, -0.160328597, -0.175813615, -0.155249029, -0.134564802, 0.03688832, 0.00175688602, 0.0274196267, + -0.000853069301, -0.148070648, 0.127308667, -0.0330546238, -0.0619701967, 0.10884852, 0.157836109, 0.055700697, + 0.153069854, -0.124244392, -0.137883157, -0.127520815, 0.00354694598, -0.116212271, -0.130330548, -0.172464535, + -0.0554537289, -0.16244705, 0.0298838317}, + {-0.00313924649, 0.104636811, -0.00189121044, -0.141974926, -0.0459853336, 0.0295766182, -0.0416731611, 0.134431586, + -0.0257469825, 0.159541234, -0.124537222, -0.134646863, -0.0754638314, 0.0348843262, 0.189903527, -0.0117872646, + 0.0253215488, 0.033129666, -0.134995311, -0.169793919, 0.082692869, 0.0133447172, -0.180572212, 0.166683719, + -0.154386878, 0.141032755, -0.189054862}, + {-0.0157399364, -0.087899588, 0.101300925, 0.0672744438, -0.160007596, -0.173225313, 0.1604743, 0.18511425, + -0.137313977, -0.00302829966, -0.00116172887, 0.139291197, -0.178774625, 0.018830156, 0.0842981339, -0.106627382, + 0.0513799004, -0.090098314, 0.102730826, 0.138699085, 0.175227448, 0.119384348, -0.00873668771, -0.140533715, + 0.174934387, -0.0292702075, -0.0563953742}, + {0.146324888, 0.165004328, -0.115809716, -0.0813532025, -0.0681633428, 0.0477341898, -0.0970991328, -0.109762929, + 0.0805196837, -0.0247990042, 0.128147095, -0.130630851, -0.137946323, 0.126800254, 0.0682550222, -0.101892732, + 0.0621065609, -0.114361145, -0.0676818863, 0.0155905169, -0.0559272915, -0.0775655061, -0.11619658, -0.123850182, + 0.0333352275, 0.0619759336, -0.153737575}, + {0.0728290975, -0.137139767, 0.171155334, -0.10935317, -0.113652103, 0.083894819, 0.0325784646, -0.136270553, + -0.117715009, -0.143446118, 0.0577968471, 0.169665903, -0.107519746, -0.149352536, 0.186078683, 0.0730377287, + 0.164606273, 0.164737105, 0.0709791556, -0.0945216864, -0.0961282775, -0.127035677, -0.079149574, -0.116503082, + -0.114481702, -0.0802296549, 0.0924181715}, + {-0.0830421597, -0.0239430889, 0.18813023, 0.185782596, 0.169754803, 0.0404542163, -0.063200362, 0.00196542731, + -0.163821682, 0.172906876, -0.0139531577, 0.0680508614, 0.184245452, 0.0418433659, 0.0777508989, -0.18665041, + -0.169096172, -0.0162949227, -0.0643856525, 0.106869876, -0.169687226, -0.140021294, 0.142271087, 0.101354837, + -0.142958999, -0.0325520597, -0.0696607158}, + {-0.0143544786, 0.152615175, 0.0869480297, 0.0572121032, -0.123094432, -0.0476713292, 0.0631705374, 0.142265052, + -0.152431101, 0.112096898, -0.171024382, 0.113088079, -0.0978072286, -0.0404484123, 0.0446099453, 0.111795463, + 0.133996516, 0.0249953847, -0.0176241957, -0.0798011646, 0.137617484, -0.114853017, 0.0865345746, 0.0806269348, + -0.153808579, 0.100480415, 0.0400802419}, + {0.00885846373, 0.104530975, 0.0511356592, 0.15449053, 0.0266832169, 0.151018828, 0.00052185799, -0.0662509352, + 0.134233072, 0.135463342, -0.132513165, 0.106484361, -0.0549784414, -0.127461627, -0.0177660231, -0.184229344, + -0.067264393, 0.0331441872, 0.0296899974, 0.112480991, -0.0866794065, -0.0769045502, 0.188820049, -0.163503736, + -0.121939979, -0.0769513547, 0.187178373}, + {0.0700233802, -0.155490026, -0.0502671041, -0.0314835422, 0.158927277, -0.0542646535, -0.103660561, -0.0306020491, + -0.0201568827, 0.0681313649, 0.166806385, 0.121379897, -0.0575036965, -0.0201710835, 0.0956908464, 0.0947490856, + -0.0557131097, 0.116438366, -0.106281899, -0.0817660689, -0.00162857235, 0.0423404239, 0.183730364, -0.115942039, + 0.0232274868, -0.135886878, 0.0707694218}, + {-0.0617577545, -0.0327048972, -0.0578244217, -0.133904487, -0.0658558309, -0.133602962, -0.178279325, 0.0863033906, + -0.109837979, 0.0180644952, -0.173991039, 0.079782702, 0.119043894, 0.174958751, 0.0709607825, -0.181912556, + -0.114235304, -0.0365099385, 0.133480966, 0.0175383482, 0.0485932231, 0.0462628603, -0.0830994919, 0.0175168738, + -0.134287432, -0.171605304, 0.17739737}, + {-0.0979685336, 0.0779526308, -0.134874135, 0.0924571678, -0.143309474, -0.00583782606, -0.0692039207, 0.0361159593, + -0.161315486, 0.17230463, 0.0166760087, -0.0615356565, 0.0799215212, 0.155071229, -0.0697915256, 0.0667596012, + -0.0682204217, 0.00894743204, -0.100012764, 0.00765745807, -0.0964676291, 0.0617717281, -0.0885751843, 0.135445908, + 0.144291341, 0.0619578063, -0.0597544722}, + {0.0257771518, 0.00839496963, 0.183237866, -0.0638526678, 0.0440821014, -0.0440427773, -0.0389030948, 0.149784356, + -0.0143964393, 0.110475667, 0.0401583351, 0.00584319467, 0.0534138083, 0.0753016546, -0.00891145878, 0.0102705108, + -0.0423660725, 0.0484866574, -0.129252583, 0.00972307287, -0.13777107, -0.091733031, 0.0791747421, 0.0705575794, + 0.135760963, -0.0341211222, 0.121966042}, + {-0.0696671829, -0.149438843, -0.130492121, 0.177022442, -0.143035844, 0.098975867, -0.162524551, 0.00240045041, + -0.0190207809, 0.0121191414, 0.0504639931, 0.114002816, -0.0101310015, -0.180998564, 0.119831644, -0.00818612985, + 0.187143385, 0.071159713, -0.147755519, 0.0786489844, -0.121551186, -0.00183718244, 0.13491042, 0.0133667644, + 0.07812123, -0.123505898, -0.160103157}, + {-0.172112495, 0.047226578, -0.132970944, 0.00720864674, 0.152551115, -0.126522362, -0.152778402, -0.185840935, + 0.134551585, -0.0125626298, -0.0831752196, 0.147344619, -0.102264144, -0.100941405, -0.0614335164, 0.0166970007, + -0.0282396376, 0.107446246, -0.162306622, -0.19101496, -0.144947544, 0.0408506282, 0.127426147, -0.128486633, + -0.155436695, -0.146092668, 0.0234605074}, + {-0.0741331354, 0.106235877, 0.0690242127, -0.16472809, -0.181256726, 0.190120652, -0.162810996, 0.0248265099, + 0.19036676, -0.0752404705, -0.0915843695, 0.119827881, 0.181097895, 0.115481257, 0.185464412, 0.0183073357, + -0.0155444955, -0.174394086, -0.0819184929, -0.109769538, 0.000563772744, -0.0847794786, -0.00350856432, -0.0628694966, + -0.0179150756, -0.0810985491, -0.126991019}, + {-0.112713069, -0.00571277039, -0.0348120145, 0.0167814046, 0.190228537, -0.18003732, 0.0719320029, 0.0788488984, + -0.0439460538, -0.0266490784, -0.0554190166, 0.0470339581, 0.159357011, 0.111465015, -0.00813783705, -0.104845144, + 0.113576166, 0.110620111, 0.1575692, -0.102988459, -0.146075591, 0.184503958, 0.0661398545, -0.0250458568, + -0.178060576, -0.120860539, -0.156311631}, + {0.0585983433, 0.172278598, 0.14716807, -0.0859363452, -0.00157456717, 0.179562241, 0.151851803, 0.141548663, + 0.0378112011, 0.126050696, -0.0815500915, -0.129984528, -0.173152581, -0.126608431, 0.161061004, 0.0161189809, + 0.040336661, -0.0963128209, 0.191107467, -0.183932319, -0.0883699432, -0.0928919166, 0.191592276, 0.185421556, + -0.0230288804, 0.144815132, -0.0992096886}, + {-0.0425618365, -0.0824135095, -0.00218332885, 0.0137943765, -0.0560813248, 0.112554401, 0.0145771299, 0.181795582, + 0.160340831, 0.110307366, -0.165677637, 0.118828632, -0.171116546, -0.0625127256, 0.0201217365, -0.0313180201, + -0.0169985034, -0.123889737, 0.0731810257, -0.110239938, 0.10873989, 0.0658772811, -0.163778186, -0.116613321, + -0.0143647799, 0.180781782, -0.177158162}, + {0.133387432, 0.0623934977, -0.110980526, -0.149483681, -0.10800685, -0.0617179051, 0.13047111, -0.188829482, + 0.152309194, 0.0937611386, 0.0319736972, 0.10286136, 0.0105889896, 0.0864559263, 0.190622315, -0.189341813, + 0.113896154, -0.0411616042, -0.0158305112, 0.0760876164, -0.102831379, 0.149824545, 0.186222047, -0.0857870802, + 0.127207607, -0.00252656173, -0.0751904324}, + {0.0976537466, 0.183089226, 0.191252947, 0.169405237, 0.0565770753, 0.0308590215, -0.0890728608, 0.165089995, + -0.0235944875, -0.174205527, 0.149395138, 0.00538947387, -0.074993521, -0.16621998, -0.0696545169, -0.0117289918, + -0.169055685, 0.119495571, -0.102552958, -0.0727175102, -0.0130539984, 0.13449125, 0.0830938965, -0.132968262, + -0.165452138, -0.134777039, -0.137075678}, + {-0.168154478, -0.0583992302, -0.0769243315, -0.0277509075, -7.82316692e-06, -0.0963165164, 0.162911013, 0.0880101696, + -0.0459401384, 0.0769917071, -0.0872795209, 0.171630532, -0.0652932078, -0.169877291, -0.119879529, -0.0265173018, + -0.0456173234, 0.101406142, -0.0257242937, -0.0282195397, -0.112852991, 0.0621854812, 0.0739964694, 0.18534255, + 0.108109124, 0.170073316, -0.175988227}, + {0.183824793, 0.0024573463, 0.106970042, 0.0831734538, -0.15550153, -0.177309573, -0.0365483463, 0.121959455, + 0.0346980616, -0.0811878368, -0.165932223, 0.0298062898, 0.0384027809, 0.160088792, 0.063925229, -0.181167364, + -0.12850219, 0.124678314, -0.188538134, 0.185204282, -0.189522326, 0.10494893, 0.164910138, -0.0762996674, + 0.0537083596, -0.170038894, -0.119950578}, + {0.141063854, -0.144242704, -0.167372018, -0.132202536, -0.103071921, 0.0973923504, 0.0434144028, -0.0436901636, + 0.110136382, -0.0848195329, -0.132071301, 0.0828088894, -0.079655692, 0.0747310892, 0.146783873, -0.0524828508, + -0.00397726614, 0.189144954, -0.180474311, -0.0347960256, 0.135975629, 0.0378963165, -0.0831586346, 0.190199673, + -0.0476226211, -0.176038012, -0.0895690694}, + {0.052432403, 0.181840301, 0.152397126, 0.156461731, 0.0861286893, 0.160564005, 0.159211308, 0.0706244111, + -0.099683091, 0.0167279262, -0.0137695307, -0.00443915417, 0.00720713288, -0.0894288495, -0.165019587, -0.149760082, + -0.104386285, 0.137890667, 0.0618288741, 0.146516219, 0.0124827232, 0.00781871658, -0.169836596, -0.144013658, + 0.0196476206, 0.0950021073, 0.121752203}, + {-0.112817958, 0.185753524, 0.00557158608, -0.0109010441, -0.0782630965, -0.0806340501, -0.10111735, 0.0457602963, + 0.120691486, 0.00453170156, 0.151166484, 0.0751216039, 0.108121008, -0.0970771536, 0.173091814, -0.0747247785, + 0.0542236306, 0.19191651, -0.173553661, 0.173040032, -0.161778599, 0.0383385643, -0.0506472066, 0.0179319605, + 0.160089046, -0.178128138, 0.0664922148}, + {0.0366745256, 0.0471229739, 0.169789612, -0.084402591, 0.109215677, -0.169242054, -0.116932303, 0.139629006, + -0.0954968259, 0.0165600851, -0.136712074, -0.156285062, -0.0361499824, 0.182008088, -0.0350765325, 0.00211337931, + -0.0855448171, 0.0245682094, 0.0464674309, -0.131790042, 0.034408927, 0.125363752, 0.176913232, -0.043239288, + 0.0827307478, -0.181739643, 0.0112358117}, + {0.0144095169, 0.00284632505, -0.0215774644, 0.0305804852, -0.107226044, -0.0641560927, -0.0807632133, -0.12648356, + -0.111151993, 0.122825675, -0.158936992, 0.0704894662, 0.0551847108, -0.13760221, 0.0400784761, -0.191738755, + 0.109209187, -0.0604826696, -0.0762268528, 0.0150504429, -0.139007673, -0.0462272987, 0.112543508, -0.063554123, + -0.0101354523, 0.152196571, -0.0566700809}, + {-0.063454099, 0.0813964754, -0.0560451001, 0.0932600424, -0.144905448, -0.00968728308, 0.135903224, -0.132450759, + -0.0417267531, 0.18930681, -0.0313318074, 0.115957439, 0.0696791336, 0.00930241123, 0.0877015591, 0.176935628, + -0.125881702, -0.157381192, 0.00996565912, -0.0682013854, -0.032698337, 0.0669107884, -0.0333003551, 0.111868031, + 0.0817616135, 0.0879792422, 0.183676347}, + {-0.101876535, -0.0104824929, 0.0341939144, -0.0777638629, 0.133748263, -0.14250128, -0.189761177, 0.174468651, + 0.0547308549, -0.155634582, 0.0136336926, 0.17732133, 0.0430501066, -0.11482209, -0.0433231145, -0.0201463755, + 0.132160082, 0.00435894914, 0.0227369908, -0.0649955124, 0.105599009, 0.00653213775, 0.146385536, -0.0674876869, + 0.0294649601, -0.0090828808, -0.189336121}, + {0.0769183412, -0.125024021, 0.053625606, 0.0538041629, 0.0357543267, -0.0592478476, 0.187969044, -0.177021101, + 0.125945807, -0.161945999, 0.0929299816, 0.0210872889, 0.000958877092, -0.131491765, -0.160294101, -0.00322358077, + -0.0965539888, 0.040743947, 0.119368978, 0.0849793032, 0.125941098, 0.156988382, 0.134143472, 0.185445666, + -0.110497095, -0.123710997, -0.0286602527}, + {-0.0942880884, 0.146827623, -0.118274562, 0.153782561, 0.0447115563, 0.0343228504, 0.0744526684, 0.121209852, + 0.0476997532, 0.109625898, 0.0666825846, 0.0837239474, 0.0330547392, -0.0563511439, 0.159424767, 0.144840434, + 0.0582646765, 0.120864898, 0.0491940938, -0.106492892, -4.61130958e-06, 0.0812624693, 0.0574826598, 0.108005241, + -0.1343503, -0.0793560296, -0.184536964}, + {-0.0628152788, -0.164782599, 0.0396851376, 0.0293482784, -0.182056263, -0.0132869035, -0.103715576, 0.187516153, + -0.128356025, -0.150966629, -0.0510631204, 0.164321005, -0.190672413, -0.0770187378, -0.136947826, -0.171093762, + 0.0896726996, -0.0189764574, 0.0454147905, -0.10565538, 0.140958905, 0.0320267156, -0.188845426, -0.0686342269, + 0.109327771, 0.191402107, -0.0299364384}, + {0.0325032175, -0.0461030006, -0.112160034, -0.0515950471, -0.0900985226, -0.0750244707, -0.12549074, 0.0423892923, + -0.132532805, -0.0953801647, 0.14049311, -0.162600145, -0.0264430624, -0.11026527, -0.129168019, -0.0531903766, + -0.0571733341, -0.00750932284, -0.163403079, 0.0955372751, 0.0415849723, 0.0813293681, -0.0840425193, -0.0836364478, + 0.0382208973, -0.15660198, -0.156168073}, + {-0.0912978947, -0.0246387087, -0.0419166423, 0.0880150571, -0.169973716, -0.1347256, 0.145546168, 0.0612329841, + 0.045314718, -0.166863248, -0.0328776948, 0.0297039691, -0.0466538817, 0.0848351792, -0.017866645, 0.038259048, + -0.101802342, -0.0137127955, -0.122804061, 0.0834453627, 0.0132888993, 0.135187417, 0.0106342537, 0.133610189, + 0.0914034769, 0.00441802479, -0.0991756842}, + {-0.133505166, 0.163291335, 0.0198537298, -0.0426343791, -0.120026812, -0.150921255, 0.143983811, -0.119658761, + -0.183134139, 0.112082422, 0.0189201571, -0.0167830791, -0.108928375, 0.0445165485, -0.168284804, 0.186435729, + -0.0850297287, -0.122995764, 0.160612479, 0.134328142, -0.177498892, -0.147127301, 0.0441274345, 0.0632432178, + 0.00436131237, 0.16817756, 0.175170064}, + {-0.171416506, 0.174026579, -0.0195435323, -0.176086023, 0.0537189804, 0.0327142142, 0.114546195, -0.158447057, + 0.153348625, -0.162123665, -0.00728371274, -0.15142642, -0.0942928642, -0.154955193, -0.0860279724, 0.18068549, + 0.126905262, -0.0358326286, -0.124668613, 0.119971067, 0.0120104421, 0.104353525, -0.121119857, -0.0603339151, + -0.112141408, 0.000847058545, 0.109019361}, + {0.107704267, 0.185612157, 0.181868419, 0.0374520458, -0.163598686, 0.0244554728, 0.0676715672, -0.00233561685, + -0.0499761589, -0.0413027443, 0.128192499, 0.116928883, -0.0427257568, -0.0267515145, 0.0636740178, -0.178925306, + -0.0467735454, -0.100876667, 0.0781042501, 0.0328268819, -0.173802942, 0.109224901, 0.0719521642, 0.0689024851, + 0.127336383, -0.0798519626, -0.0622614212}, + {-0.00613338593, 0.0581946597, -0.066634573, -0.10905534, -0.0273437351, -0.11439269, 0.0359120071, -0.099061735, + -0.0802826509, -0.0424083546, -0.00459499797, 0.0288921483, -0.158087179, 0.0738640949, 0.0993480459, -0.157756731, + -0.00917779095, -0.0205190424, -0.0909724683, 0.141723961, 0.167598695, 0.0142846443, 0.0503009669, -0.0150258495, + 0.0280418098, 0.138684884, -0.0939480662}, + {0.144854009, -0.117241286, -0.0165551752, -0.00811778568, -0.145114034, 0.136766046, -0.187149063, 0.159925401, + -0.0445792973, -0.0670291483, 0.0939136818, -0.0551887713, -0.179524243, -0.00257217023, 0.013442128, 0.126009971, + 0.159998074, 0.0583294854, 0.161778823, -0.0158883706, -0.109346196, 0.15250434, 0.0154327918, 0.0118686622, + -0.0652717352, -0.137885705, -0.131062776}, + {-0.0285933539, 0.0723075122, -0.0489430167, -0.18787235, 0.076197207, 0.0307388976, -0.116385281, -0.0333909728, + -0.125749126, -0.0238971375, 0.0504999645, -0.0488478988, 0.0281658787, -0.175939426, 0.136543989, -0.179561988, + -0.054677926, 0.1509417, 0.0698438585, 0.0472450927, 0.00885908306, -0.00329366792, 0.180733606, 0.128414467, + 0.189176291, -0.116094947, -0.0597007684}, + {0.102558345, -0.178428128, -0.0599471405, 0.136943847, 0.0849165097, 0.00182504626, -0.0532353222, 0.16186665, + 0.054078754, -0.171150476, -0.159895867, -0.0469925478, -0.151459455, -0.101407215, 0.0280825533, 0.106846616, + -0.00328999734, 0.00643474981, -0.126369044, -0.169612631, -0.0035712414, -0.0620421879, 0.190395027, -0.0989916027, + 0.085333772, -0.0449582264, 0.162536532}, + {-0.0144940568, 0.0875491053, 0.0193265714, -0.0427722819, -0.0137878619, 0.122514509, -0.118327513, -0.144594491, + 0.039245639, -0.167635649, -0.131826565, 0.0791596472, -0.106716782, 0.138579577, 0.0573720112, 0.146468818, + 0.126111582, -0.0891450569, -0.187989116, -0.110069141, 0.0265749078, 0.0485910662, 0.127895728, -0.136718288, + 0.00486727152, 0.074877277, 0.0841798261}, + {-0.115947045, -0.0815744326, 0.0962111205, 0.124095641, -0.000113309739, -0.050789699, 0.169500813, -0.0543582775, + 0.0490500182, 0.107391484, 0.0940941423, -0.0788560286, -0.119959407, -0.129166201, -0.0883254334, -0.00658770325, + -0.144865111, 0.104666039, 0.0673807561, 0.128282934, 0.0518612638, 0.0407452546, 0.119319059, -0.0195252486, + 0.118702404, -0.0513600335, -0.023790434}, }; const float FIVE_dense_biases[FIVE_DENSE_NUM] = { - 0.0607186109, -0.0681320056, 0.00174399419, -0.0552374087, 0.169119328, 0.059536662, 0.121260114, 0.0594619587, - 0.123958312, 0.142431423, -0.066357702, 0.1571486, 0.0430835485, 0.0681126416, 0.218000457, 0.0866415352, - -0.0935378969, 0.18506594, -0.0619109422, -0.0327474251, 0.279266626, 0.247783005, 0.0759725198, 0.267866522, - 0.0564821772, 0.162609458, 0.116303787, 0.0144420909, 0.0144254379, 0.0594321191, 0.0713874102, 0.120119229, - -0.0792147592, 0.151572526, 0.0799025595, 0.241775259, 0.132559836, 0.221947417, -0.0514785275, 0.188967034, - 0.196275517, 0.0211338401, 0.128358856, -0.0350252055, 0.194681481, 0.125860646, -0.104203798, 0.0794227272, - -0.0228515472, 0.156887457, 0.10330575, 0.18149218, 0.160906896, 0.250343442, 0.239296943, 0.0897175968, - 0.0577574857, -0.0525054261, -0.0180928297, -0.0237387344, -0.0620574579, -0.0873452052, 0.0453474857, 0.117129661 + 0.184154049, -0.0378458425, 0.183093876, -0.0080242753, 0.102332413, 0.183470353, -0.104653649, 0.180053473, + 0.0481173173, -0.152572319, 0.0127777783, -0.0312985182, 0.0399781056, 0.118381582, -0.173663497, 0.0267720241, + 0.0292022303, 0.14473331, 0.189653888, -0.151288509, 0.116915807, 0.0336895622, -0.175192595, -0.120204777, + 0.095160082, 0.183481187, -0.162827566, -0.064959608, -0.189971775, -0.17095466, -0.191529781, 0.0670864582, + -0.136453718, 0.100945257, -0.157902598, 0.0227670446, -0.0594408363, 0.000920747756, -0.133156687, 0.0797674879, + 0.135855094, -0.0125222057, -0.187858924, -0.105459847, -0.105646022, 0.0555062182, 0.188671499, -0.0521565042, + 0.00194925338, -0.00793262292, 0.0186251029, 0.00244897255, 0.12571308, -0.14607656, -0.0890545547, -0.183423445, + -0.141658604, -0.0616963618, -0.025944123, 0.0540205278, -0.152142838, -0.0668404996, 0.176948458, -0.0250180755 }; const float FIVE_logit_weights[FIVE_DENSE_NUM] NN_ALIGNED = { - 0.366290689, -0.179763243, -0.170635402, 0.358551443, -0.301865429, -0.204198688, -0.18824023, 0.368638158, - 0.29080224, -0.110242181, 0.260225922, 0.333086222, -0.242419481, 0.257134348, -0.183402345, -0.260596663, - -0.272571802, 0.304102749, 0.33268097, 0.333681524, -0.446022332, -0.248471856, -0.232226282, -0.329673767, - -0.238541022, -0.486667186, -0.209973752, 0.601931572, 0.395690441, 0.195730135, 0.266417474, -0.295594722, - 0.409933716, -0.158102736, 0.31490761, -0.293863147, -0.134037212, -0.291068882, 0.193977296, -0.144613206, - 0.299789637, -0.232466415, -0.251558155, -0.20994027, -0.279022664, -0.185697749, 0.142207414, 0.255289674, - -0.258415729, -0.143972635, 0.151671469, -0.366263509, -0.123788796, -0.322885275, -0.363797396, -0.156830251, - 0.550342262, 0.203263223, -0.183517739, -0.203325212, -0.108895399, 0.191670418, -0.131806001, 0.275587142 + -0.0772386044, -0.0170361251, -0.0426058918, 0.0888897926, 0.0727625042, 0.122489706, 0.0608881712, -0.0408361405, + 0.118295908, 0.037237674, 0.0149261355, 0.120876253, -0.0685143024, 0.100188315, -0.0480415374, 0.124152735, + -0.0264933854, 0.108507723, 0.101005271, 0.0470455289, 0.0472079217, -0.12096563, -0.000403001904, -0.0012858808, + -0.0941059142, -0.108057931, 0.0379516929, 0.0377163738, -0.0350441337, -0.0614878684, 0.0228298008, -0.118863195, + -0.0860731304, -0.098130703, -0.0383326858, -0.11350739, 0.0641452819, 0.0606613606, 0.0704503208, -0.0973125994, + 0.0247275382, 0.0464537442, 0.119046345, -0.0689847767, -0.0681778938, -0.117268726, -0.0113481879, -0.0933452249, + -0.00120897591, 0.00429883599, 0.0202691704, -0.023321867, 0.0216833055, 0.0654085726, 0.000852569938, 0.121629402, + 0.045461446, 0.0234107673, 0.0507824719, 0.0449485183, -0.112117022, -0.00845275819, 0.0772273093, -0.0543818772 }; -const float FIVE_logit_bias = -0.0882488862; +const float FIVE_logit_bias = 0.077988714; #endif \ No newline at end of file diff --git a/src/nn_train.py b/src/nn_train.py index 4de0a5a..f82a369 100755 --- a/src/nn_train.py +++ b/src/nn_train.py @@ -33,26 +33,23 @@ # You should have received a copy of the GNU General Public License # along with ctak. If not, see . -from collections.abc import Iterator -from dataclasses import dataclass -from itertools import product -from math import log, ceil - import argparse import concurrent.futures import json +import math import os -from pathlib import Path +import random import subprocess +from collections.abc import Iterator +from dataclasses import dataclass +from itertools import product +from pathlib import Path import numpy as np import torch -from tqdm import tqdm - -from torch.nn import Embedding, MSELoss, Linear, Module -from torch.nn.functional import silu, tanh from torch import Tensor - +from torch.nn import Embedding, Linear, Module, MSELoss +from tqdm import tqdm # =================================================================== # Net dimensions @@ -106,6 +103,9 @@ class DataGenConfig: games: int procs: int replay_iters: int + root: Path + train_only_self_play: bool + k: float @dataclass(frozen=True) @@ -116,292 +116,393 @@ class TrainingGridSearchConfig: lr: list[float] val_frac: list[float] - def make_configs(self) -> list[CandidateTrainingConfig]: + def make_configs(self, data_gen_config: DataGenConfig) -> list["Candidate"]: + inp_dim, hidden = NET_DIMS[data_gen_config.size] flds = self.__dataclass_fields__.keys() - return [ - CandidateTrainingConfig(**dict(zip(flds, vals))) - for vals in product(*(getattr(self, k) for k in flds)) + almost_cands = [ + dict(zip(flds, vals)) for vals in product(*(getattr(self, k) for k in flds)) ] + for ident, almost_cand in enumerate(almost_cands): + net = Net(inp_dim, hidden) + net.to_c( + size=data_gen_config.size, + ident=ident, + path=data_gen_config.root + / "include" + / f"cand_{ident}_weights_{data_gen_config.size}.c", + note=f"{ident=}, v000, random init", + ) + cand_copy_for( + 6 if data_gen_config.size == 5 else 5, ident, data_gen_config.root + ) + almost_cand["net"] = net + almost_cand["train_only_self_play"] = data_gen_config.train_only_self_play + return [Candidate(**d) for d in almost_cands] -@dataclass(frozen=True) -class CandidateTrainingConfig: +@dataclass +class Candidate: + train_only_self_play: bool smooth_factor: float epochs: int batch: int lr: float val_frac: float + net: "Net" + elo: float = 1500.0 + rated_games: int = 0 def __str__(self) -> str: - return f"(λ={self.smooth_factor}, E={self.epochs}, BS={self.batch}, η={self.lr}, V%={self.val_frac * 100.0:.1f})" + return f"(λ={self.smooth_factor}, E={self.epochs}, BS={self.batch}, η={self.lr:.2e}, V%={self.val_frac * 100.0:.1f})" + def training_pool(self, pool: Pool) -> Pool: + if self.train_only_self_play: + return pool.select_chains(pool.chain_self_play) + return pool -# =================================================================== -# Self-play records -# =================================================================== + def fit(self, pool: Pool) -> tuple[float, float]: + # The train/val split is fixed but targets are refreshed + split = DataSplit.build(self.training_pool(pool), self.val_frac) + if split.n == 0: + return math.nan, math.nan + optimizer = torch.optim.AdamW(self.net.parameters(), lr=self.lr) + loss_fn = MSELoss() -def smooth( - leaf_values: Tensor, - result: float, - lam: float, -) -> Tensor: - # Smooth(leaf_values, result, lambda), rooted at the game outcome: - # G[-1] = result, G[t] = (1-lambda)V[t] + lambda G[t+1] - targets = torch.empty_like(leaf_values) - targets[-1] = result + pbar = tqdm(range(self.epochs), desc="train", unit="ep") + for _ in pbar: + split.refresh_targets(self.net, self.smooth_factor) - for ply in range(len(leaf_values) - 2, -1, -1): - targets[ply] = (1.0 - lam) * leaf_values[ply] + lam * targets[ply + 1] + self.net.train() + for head, cells, parity, target in split.batches(self.batch): + optimizer.zero_grad() + predictions = self.net(head, cells) * parity + loss = loss_fn(predictions, target) + loss.backward() + optimizer.step() - return targets + with torch.no_grad(): + self.net.eval() + val = split.val_idx + predictions = self.net(split.pool.head[val], split.pool.cells[val]) + predictions = predictions * split.pool.parity[val] + targets = split.targets[val] + mse = loss_fn(predictions, targets).item() + corr = torch.corrcoef(torch.stack([predictions, targets]))[0, 1].item() + pbar.set_postfix(val_corr=f"{corr:.4f}", val_mse=f"{mse:.4f}") -SPOOKY: int = 4 + return corr, mse -@dataclass -class Performance: - win: int - loss: int - draw: int +# =================================================================== +# Self-play records: games (for ratings) and chains (for training) +# =================================================================== - def rate(self) -> float: - return float(self.win) / float(max(1, self.win + self.loss + self.draw)) - def __str__(self) -> str: - global SPOOKY - return f"+{str(self.win).zfill(SPOOKY)}-{str(self.loss).zfill(SPOOKY)}={str(self.draw).zfill(SPOOKY)}" +@dataclass(frozen=True) +class Games: + black: np.ndarray # [G] candidate id playing black + white: np.ndarray # [G] candidate id playing white + result: np.ndarray # [G] outcome from black's perspective, {-1, 0, 1} + newest: np.ndarray # [G] game comes from the last loaded file + + def head_to_head(self) -> Iterator[tuple[int, int, float]]: + for i in np.flatnonzero(self.newest & (self.black != self.white)): + black, white, result = ( + int(self.black[i]), + int(self.white[i]), + float(self.result[i]), + ) + # elo score: 1 win, 0.5 draw, 0 loss, from a's perspective + yield black, white, (result + 1.0) / 2.0 @dataclass(frozen=True) -class DataSplit: - train_positions: Tensor - train_targets: Tensor - train_parity_signs: Tensor - val_positions: Tensor - val_targets: Tensor - val_parity_signs: Tensor - - def batches(self, batch_size: int) -> Iterator[tuple[Tensor, Tensor, Tensor]]: - order = torch.randperm( - len(self.train_positions), device=self.train_positions.device +class Pool: + head: Tensor # [n, 2] fixed head inputs of the root state s_t + cells: Tensor # [n, n_cells] cell states 0..6 of s_t + leaf_head: Tensor # [n, 2] head inputs of the PV leaf pv_t + leaf_cells: Tensor # [n, n_cells] cell states of pv_t + parity: Tensor # [n] +1 when black is to move at s_t + leaf_parity: Tensor # [n] +1 when black is to move at pv_t + terminal: Tensor # [n] leaf is an exact terminal + terminal_value: Tensor # [n] exact terminal value, black's perspective + chain_lens: Tensor # [C] rows per chain + chain_result: Tensor # [C] game result, black's perspective + chain_self_play: Tensor # [C] chain comes from a self vs self game + + @classmethod + def empty(cls, n_cells: int) -> "Pool": + def rows(dtype: torch.dtype, width: int = 0) -> Tensor: + return torch.empty((0, width) if width else (0,), dtype=dtype) + + return cls( + head=rows(torch.float32, 2), + cells=rows(torch.uint8, n_cells), + leaf_head=rows(torch.float32, 2), + leaf_cells=rows(torch.uint8, n_cells), + parity=rows(torch.float32), + leaf_parity=rows(torch.float32), + terminal=rows(torch.bool), + terminal_value=rows(torch.float32), + chain_lens=rows(torch.int64), + chain_result=rows(torch.float32), + chain_self_play=rows(torch.bool), ) - for start in range(0, len(order), batch_size): - idx = order[start : start + batch_size] - yield ( - self.train_positions[idx], - self.train_targets[idx], - self.train_parity_signs[idx], - ) + @property + def n_rows(self) -> int: + return self.head.shape[0] -@dataclass(frozen=True) -class CandidateRecords: - positions: Tensor # [n, inp_dim] net input of the root state s_t - leaf_positions: Tensor # [n, inp_dim] net input of the PV leaf pv_t - game_ids: Tensor # [n] - results: Tensor # [n] game result R, black's perspective - cand_results: Tensor # [n] R from the recorded candidate's perspective - parity_signs: Tensor # [n] root parity - leaf_parity_signs: Tensor # [n] leaf parity - leaf_terminals: Tensor # [n] leaf is an exact terminal - leaf_terminal_values: Tensor # [n] exact terminal value, black's perspective - - def performance(self) -> Performance: - result = Performance(0, 0, 0) - for game_id in torch.unique(self.game_ids): - in_game = self.game_ids == game_id - game_result = self.cand_results[in_game][0].item() - match game_result: - case 1: - result.win += 1 - case -1: - result.loss += 1 - case _: - result.draw += 1 - return result - - def make_training_data( - self, model: Module, training: CandidateTrainingConfig - ) -> DataSplit: - model.eval() - with torch.no_grad(): - # Net(pv_t), black's perspective; exact terminals override the net - leaf_values = model(self.leaf_positions) * self.leaf_parity_signs - leaf_values = torch.where( - self.leaf_terminals, self.leaf_terminal_values, leaf_values - ) + def select_chains(self, keep: Tensor) -> "Pool": + keep = keep.bool() + rows = torch.repeat_interleave( + torch.arange(self.chain_lens.shape[0], dtype=torch.int64), self.chain_lens + ) + idx = torch.nonzero(keep[rows]).flatten() + return Pool( + head=self.head[idx], + cells=self.cells[idx], + leaf_head=self.leaf_head[idx], + leaf_cells=self.leaf_cells[idx], + parity=self.parity[idx], + leaf_parity=self.leaf_parity[idx], + terminal=self.terminal[idx], + terminal_value=self.terminal_value[idx], + chain_lens=self.chain_lens[keep], + chain_result=self.chain_result[keep], + chain_self_play=self.chain_self_play[keep], + ) - targets = torch.empty_like(leaf_values) - - for game_id in torch.unique(self.game_ids): - in_game = self.game_ids == game_id - game_result = self.results[in_game][0].item() - # self-pair games (i,i) record the candidate on every ply, - # so smooth one chain per colour, not across players - for sign in (1.0, -1.0): - idxs = torch.nonzero( - in_game & (self.parity_signs == sign), as_tuple=True - )[0] - if len(idxs) == 0: + +# =================================================================== +# Reading game records +# =================================================================== + +_ROW_FIELDS = ( + "head", + "cells", + "leaf_head", + "leaf_cells", + "parity", + "leaf_parity", + "terminal", + "terminal_value", +) + + +def _chain_arrays( + rows: list[dict], n_cells: int, source: Path +) -> dict[str, np.ndarray]: + + def column(part: str, key: str, dtype: np.dtype) -> np.ndarray: + return np.array([r[part][key] for r in rows], dtype=dtype) + + out = { + "head": column("root", "head", np.float32), + "cells": column("root", "cells", np.uint8), + "leaf_head": column("leaf", "head", np.float32), + "leaf_cells": column("leaf", "cells", np.uint8), + "parity": column("root", "parity", np.float32), + "leaf_parity": column("leaf", "parity", np.float32), + "terminal": column("leaf", "terminal", np.bool_), + "terminal_value": column("leaf", "terminal_value", np.float32), + } + for name in ("cells", "leaf_cells"): + if out[name].shape[1] != n_cells: + raise ValueError( + f"{source}: {name} width {out[name].shape[1]}, expected {n_cells}" + ) + return out + + +def _game_colours(game: dict) -> tuple[int, int]: + a, b = int(game["cand_A"]), int(game["cand_B"]) + for r in game["rows"]: + if r["root"]["parity"] > 0: + cand = int(r["cand"]) + return cand, b if cand == a else a + recorded = {int(r["cand"]) for r in game["rows"]} + return (a, b) if a not in recorded else (b, a) + + +def load_window( + files: list[Path], size: int, n_candidates: int +) -> tuple[list[Pool], Games]: + n_cells = NET_DIMS[size][0] - 2 + blocks = [{f: [] for f in _ROW_FIELDS} for _ in range(n_candidates)] + chain_lens: list[list[int]] = [[] for _ in range(n_candidates)] + chain_result: list[list[float]] = [[] for _ in range(n_candidates)] + chain_self_play: list[list[bool]] = [[] for _ in range(n_candidates)] + black, white, result, newest = [], [], [], [] + + for file_index, path in enumerate(files): + is_newest = file_index == len(files) - 1 + with open(path) as f: + for line in f: + if not line.strip(): continue - targets[idxs] = smooth( - leaf_values[idxs], game_result, training.smooth_factor - ) - - n_val = max(1, int(len(leaf_values) * training.val_frac)) - perm = torch.randperm(len(leaf_values), device=leaf_values.device) - val_idx, train_idx = perm[:n_val], perm[n_val:] - - return DataSplit( - train_positions=self.positions[train_idx], - train_targets=targets[train_idx], - train_parity_signs=self.parity_signs[train_idx], - val_positions=self.positions[val_idx], - val_targets=targets[val_idx], - val_parity_signs=self.parity_signs[val_idx], + game = json.loads(line) + game_result = float(game["result"]) + b, w = _game_colours(game) + black.append(b) + white.append(w) + result.append(game_result) + newest.append(is_newest) + + by_cand: dict[int, list[dict]] = {} + for r in game["rows"]: + by_cand.setdefault(int(r["cand"]), []).append(r) + + for cand, rows in by_cand.items(): + parity = [r["root"]["parity"] for r in rows] + for sign in (1, -1): + chain = [ + r for r, p in zip(rows, parity) if (p > 0) == (sign > 0) + ] + if not chain: + continue + for name, array in _chain_arrays(chain, n_cells, path).items(): + blocks[cand][name].append(array) + chain_lens[cand].append(len(chain)) + chain_result[cand].append(game_result) + chain_self_play[cand].append(b == w) + + def pool_of(cand: int) -> Pool: + if not chain_lens[cand]: + return Pool.empty(n_cells) + arrays = { + name: torch.from_numpy(np.concatenate(blocks[cand][name])) + for name in _ROW_FIELDS + } + return Pool( + **arrays, + chain_lens=torch.tensor(chain_lens[cand], dtype=torch.int64), + chain_result=torch.tensor(chain_result[cand], dtype=torch.float32), + chain_self_play=torch.tensor(chain_self_play[cand], dtype=torch.bool), ) + games = Games( + black=np.array(black, dtype=np.int16), + white=np.array(white, dtype=np.int16), + result=np.array(result, dtype=np.float32), + newest=np.array(newest, dtype=np.bool_), + ) + return [pool_of(c) for c in range(n_candidates)], games + -@dataclass(frozen=True) -class PlayRecords: - positions: list[Tensor] # [candidate, n_i, inp_dim] - leaf_positions: list[Tensor] # [candidate, n_i, inp_dim] - game_ids: list[Tensor] # [candidate, n_i] - results: list[Tensor] # [candidate, n_i] - cand_results: list[Tensor] # [candidate, n_i] - parity_signs: list[Tensor] # [candidate, n_i] - leaf_parity_signs: list[Tensor] # [candidate, n_i] - leaf_terminals: list[Tensor] # [candidate, n_i] - leaf_terminal_values: list[Tensor] # [candidate, n_i] - - def index(self, index: int) -> CandidateRecords: - return CandidateRecords( - positions=self.positions[index], - leaf_positions=self.leaf_positions[index], - game_ids=self.game_ids[index], - results=self.results[index], - cand_results=self.cand_results[index], - parity_signs=self.parity_signs[index], - leaf_parity_signs=self.leaf_parity_signs[index], - leaf_terminals=self.leaf_terminals[index], - leaf_terminal_values=self.leaf_terminal_values[index], - ) +# =================================================================== +# Training data: fixed rows, refreshed targets +# =================================================================== + + +@dataclass +class DataSplit: + pool: Pool + train_idx: Tensor + val_idx: Tensor + targets: Tensor # [n] aligned with pool rows, refreshed per epoch + chain_end: Tensor # [C] last row index of each chain + wave_order: Tensor # [n] rows ordered by distance from their chain's end + wave_bounds: Tensor # [d] start of distance d in wave_order + + @property + def n(self) -> int: + return self.pool.n_rows @classmethod - def load_merge(cls, files: list[Path], size: int) -> PlayRecords: - # one JSON record per line: - # {"result": R, "rows": [{"cand", "root": {...}, "leaf": {...}}]} - inp_dim = NET_DIMS[size][0] - n_cells = inp_dim - 2 - - games: list[dict] = [] - for file in files: - with open(file) as f: - for line in f: - if line.strip(): - games.append(json.loads(line)) - - def board(row_part: dict) -> list[float]: - return [*row_part["head"], *row_part["cells"]] - - n_cands = max(r["cand"] for g in games for r in g["rows"]) + 1 - fields = ( - "positions", - "leaf_positions", - "game_ids", - "results", - "cand_results", - "parity_signs", - "leaf_parity_signs", - "leaf_terminals", - "leaf_terminal_values", + def build(cls, pool: Pool, val_frac: float) -> "DataSplit": + n = pool.n_rows + if n == 0: + empty = torch.empty(0, dtype=torch.int64) + return cls(pool, empty, empty, torch.empty(0), empty, empty, empty) + + # Smoothing is G[t] = (1-λ)V[t] + λG[t+1] with G at the chain end. + # Chains are contiguous, so every row that is d plies from its chain's + # end can be updated in one vectorised wavefront step per d. + lens = pool.chain_lens + chain_end = torch.cumsum(lens, dim=0) - 1 + chain_of_row = torch.repeat_interleave( + torch.arange(lens.shape[0], dtype=torch.int64), lens + ) + dist = chain_end[chain_of_row] - torch.arange(n, dtype=torch.int64) + wave_order = torch.argsort(dist, stable=True) + wave_bounds = torch.searchsorted( + dist[wave_order], torch.arange(int(dist.max()) + 2, dtype=torch.int64) ) - per_cand = {c: {k: [] for k in fields} for c in range(n_cands)} - for game_id, game in enumerate(games): - result = float(game["result"]) - for cand in range(n_cands): - rows = [r for r in game["rows"] if r["cand"] == cand] - if not rows: - continue - for part in ("root", "leaf"): - for r in rows: - if len(r[part]["cells"]) != n_cells: - raise ValueError( - f"{files[-1]}: {len(r[part]['cells'])} cells, " - f"expected {n_cells} for size {size}" - ) - parity = np.array([r["root"]["parity"] for r in rows], dtype=np.float32) - per_cand[cand]["positions"].append( - torch.from_numpy( - np.array([board(r["root"]) for r in rows], dtype=np.float32) - ) - ) - per_cand[cand]["leaf_positions"].append( - torch.from_numpy( - np.array([board(r["leaf"]) for r in rows], dtype=np.float32) - ) - ) - per_cand[cand]["game_ids"].append( - torch.full((len(rows),), game_id, dtype=torch.int64) - ) - per_cand[cand]["results"].append( - torch.full((len(rows),), result, dtype=torch.float32) - ) - per_cand[cand]["cand_results"].append(torch.from_numpy(parity * result)) - per_cand[cand]["parity_signs"].append(torch.from_numpy(parity)) - per_cand[cand]["leaf_parity_signs"].append( - torch.from_numpy( - np.array([r["leaf"]["parity"] for r in rows], dtype=np.float32) - ) - ) - per_cand[cand]["leaf_terminals"].append( - torch.from_numpy( - np.array( - [r["leaf"]["terminal"] == 1 for r in rows], - dtype=np.bool_, - ) - ) - ) - per_cand[cand]["leaf_terminal_values"].append( - torch.from_numpy( - np.array( - [r["leaf"]["terminal_value"] for r in rows], - dtype=np.float32, - ) - ) - ) - - def merged(cand: int, k: str, empty: Tensor) -> Tensor: - blocks = per_cand[cand][k] - return torch.concat(blocks, dim=0) if blocks else empty + n_val = max(1, int(n * val_frac)) + perm = torch.randperm(n) return cls( - **{ - k: [ - merged( - cand, - k, - torch.empty( - (0, inp_dim) if k.endswith("positions") else (0,), - dtype=torch.float32 - if k not in ("game_ids", "leaf_terminals") - else (torch.int64 if k == "game_ids" else torch.bool), - ), - ) - for cand in range(n_cands) - ] - for k in fields - } + pool=pool, + train_idx=perm[n_val:], + val_idx=perm[:n_val], + targets=torch.zeros(n), + chain_end=chain_end, + wave_order=wave_order, + wave_bounds=wave_bounds, ) + def refresh_targets(self, net: Module, lam: float) -> None: + pool = self.pool + net.eval() + with torch.no_grad(): + # Net(pv_t), black's perspective; exact terminals override the net + leaf = net(pool.leaf_head, pool.leaf_cells) * pool.leaf_parity + leaf = torch.where(pool.terminal, pool.terminal_value, leaf) + + targets = torch.zeros_like(leaf) + targets[self.chain_end] = pool.chain_result + for lo, hi in zip(self.wave_bounds[1:-1], self.wave_bounds[2:]): + idx = self.wave_order[lo:hi] + targets[idx] = (1.0 - lam) * leaf[idx] + lam * targets[idx + 1] + self.targets = targets + + def batches( + self, batch_size: int + ) -> Iterator[tuple[Tensor, Tensor, Tensor, Tensor]]: + order = torch.randperm(self.train_idx.shape[0]) + train_targets = self.targets[self.train_idx] + for start in range(0, order.shape[0], batch_size): + idx = order[start : start + batch_size] + rows = self.train_idx[idx] + yield ( + self.pool.head[rows], + self.pool.cells[rows], + self.pool.parity[rows], + train_targets[idx], + ) + # =================================================================== # Network # =================================================================== +def fast_tanh(x: Tensor) -> Tensor: + # Must match fast_tanh in include/nn.c: degree-11 fit of tanh on [-3, 3], + # saturating to +-1 outside. + x2 = x * x + poly = x * ( + 0.997136032 + + x2 * ( + -0.305215124 + + x2 * (0.0832466371 + x2 * (-0.0139947924 + x2 * (0.00123106314 + x2 * -4.29748644e-05))) + ) + ) + return torch.where(x > 3.0, 1.0, torch.where(x < -3.0, -1.0, poly)) + + +def fast_silu(x: Tensor) -> Tensor: + # Must match fast_silu in include/nn.c: [4,2] Pade approximant with cutoff. + # The cutoff below is evaluated at x = 0 (instead of x) because torch + # evaluates both branches of where: 1 + 0.1 * x is 0 for x = -10. + xs = torch.where(x < -4.6, 0.0, x) + poly = xs * (0.5 + xs * (0.25 + xs * (0.05 + 0.004167 * xs))) / (1 + 0.1 * xs) + return torch.where(x < -4.6, 0.0, torch.where(x > 4.6, x, poly)) + + class Net(Module): def __init__(self, inp_dim: int, hidden: int) -> None: super().__init__() @@ -410,56 +511,24 @@ class Net(Module): self.hidden = Linear(inp_dim, hidden, bias=True) self.output = Linear(hidden, 1, bias=True) - def forward(self, x: Tensor) -> Tensor: - # x: [n, 2 + n_cells]; the first 2 columns are the fixed head - # inputs, the rest are raw cell states (0..6) - n = x.shape[0] - inp = torch.cat([x[:, :2], self.embedding(x[:, 2:].long()).view(n, -1)], dim=1) - hidden = silu(self.hidden(inp)) - return tanh(self.output(hidden)).squeeze(-1) - - def fit( - self, *, records: CandidateRecords, config: CandidateTrainingConfig - ) -> tuple[float, float]: - # training widgets - optimizer = torch.optim.AdamW(self.parameters(), lr=config.lr) - loss_fn = MSELoss() - - pbar = tqdm(range(config.epochs), desc="train", unit="ep") - for _ in pbar: - split = records.make_training_data(self, config) - - self.train() - for positions, targets, parity_signs in split.batches(config.batch): - optimizer.zero_grad() - predictions = self(positions) * parity_signs - loss = loss_fn(predictions, targets) - loss.backward() - optimizer.step() - - with torch.no_grad(): - self.eval() - predictions = self(split.val_positions) * split.val_parity_signs - mse = loss_fn(predictions, split.val_targets).item() - corr = torch.corrcoef(torch.stack([predictions, split.val_targets]))[ - 0, 1 - ].item() - - pbar.set_postfix(val_corr=f"{corr:.4f}", val_mse=f"{mse:.4f}") - - return corr, mse + def forward(self, head: Tensor, cells: Tensor) -> Tensor: + # head: [n, 2] fixed head inputs; cells: [n, n_cells] raw cell states + # (0..6) - the only place they become anything other than integers + inp = torch.cat([head, self.embedding(cells.long()).flatten(1)], dim=1) + hidden = fast_silu(self.hidden(inp)) + return fast_tanh(self.output(hidden)).squeeze(-1) def to_c( self, *, size: int, - id: int | None, + ident: int | None, path: Path, note: str, ) -> None: upper = "FIVE" if size == 5 else "SIX" - prefix = (f"cand_{id}_" if id is not None else "") + upper - guard = f"WEIGHTS_{upper}" + (f"_{id}" if id is not None else "") + prefix = (f"cand_{ident}_" if ident is not None else "") + upper + guard = f"WEIGHTS_{upper}" + (f"_{ident}" if ident is not None else "") E = self.embedding.weight.detach().cpu().numpy() W = self.hidden.weight.detach().cpu().numpy() @@ -478,7 +547,7 @@ class Net(Module): f"const float {prefix}_dense_biases[{upper}_DENSE_NUM] =\n{{\n{_fmt_flat(B)}\n}};\n\n", f"const float {prefix}_logit_weights[{upper}_DENSE_NUM] NN_ALIGNED =\n{{\n{_fmt_flat(LW)}\n}};\n\n", f"const float {prefix}_logit_bias = {LB:.9g};\n", - f"#endif", + "#endif", ] for line in lines: _ = f.write(line) @@ -537,30 +606,26 @@ def cand_copy_for(size: int, id: int, root: Path) -> None: # =================================================================== -def setup(num_candidates: int, data_gen: DataGenConfig, root: Path) -> list[Net]: - inp_dim, hidden = NET_DIMS[data_gen.size] - candidates = [Net(inp_dim, hidden) for _ in range(num_candidates)] - for id, cand in enumerate(candidates): - cand.to_c( - size=data_gen.size, - id=id, - path=root / "include" / f"cand_{id}_weights_{data_gen.size}.c", - note=f"{id=}, v000, random init", - ) - cand_copy_for(6 if data_gen.size == 5 else 5, id, root) - return candidates +def update_elo(a: Candidate, b: Candidate, score: float, k: float) -> None: + # score is a's result as an elo score: 1.0 win, 0.5 draw, 0.0 loss + ea = 1.0 / (1.0 + 10.0 ** ((b.elo - a.elo) / 400.0)) + delta = k * (score - ea) + a.elo += delta + b.elo -= delta def run_step( *, - candidates: list[Net], - data_gen: DataGenConfig, + candidates: list[Candidate], + data_gen_config: DataGenConfig, iter: int, - root: Path, - training_configs: list[CandidateTrainingConfig], ): def data_path(i: int) -> Path: - return root / "data" / f"selfplay-{data_gen.size}-v{i:03d}.json" + return ( + data_gen_config.root + / "data" + / f"selfplay-{data_gen_config.size}-v{i:03d}.json" + ) print(f"\n== iteration {iter} ==") @@ -572,30 +637,34 @@ def run_step( # 1. rebuild for i, j in cand_pairs: _ = subprocess.run( - ["make", f"selfplay-{i}-{j}"], cwd=root, check=True, capture_output=True + ["make", f"selfplay-{i}-{j}"], + cwd=data_gen_config.root, + check=True, + capture_output=True, ) # 2. generate self-play data data = data_path(iter) print( - f"selfplay: {num_candidates=}, {data_gen.games=}, " - f"{data_gen.size=}, {data_gen.depth=}, {data_gen.min_ply=}" + f"selfplay: {num_candidates=}, {data_gen_config.games=}, " + f"{data_gen_config.size=}, {data_gen_config.depth=}, {data_gen_config.min_ply=}, " + f"{data_gen_config.train_only_self_play=}" ) out_games: list[str] = [] for out in fan_out( [ [ f"./selfplay-{i}-{j}", - str(data_gen.size), - str(data_gen.depth), - str(data_gen.min_ply), + str(data_gen_config.size), + str(data_gen_config.depth), + str(data_gen_config.min_ply), ] for (i, j) in cand_pairs ], - data_gen.games, - data_gen.procs, + data_gen_config.games, + data_gen_config.procs, "selfplay", - root, + data_gen_config.root, ): out_games.extend(out.splitlines()) print(f"writing {len(out_games):,} games to {data}") @@ -604,43 +673,57 @@ def run_step( if out_games: _ = f.write("\n") - # 3. compute performance + # 3. rate every head-to-head game played in this iteration data_files = [ - data_path(i) for i in range(max(iter - data_gen.replay_iters, 1), iter + 1) + data_path(i) + for i in range(max(iter - data_gen_config.replay_iters, 1), iter + 1) ] print("Loading data from", [str(c) for c in data_files], "...", end=" ") - records = PlayRecords.load_merge(data_files, data_gen.size) - print("candidates have", [f"{r.shape[0]:,}" for r in records.results], "rows.") - results = [ - (i, cand, records.index(i).performance()) for i, cand in enumerate(candidates) - ] + pools, games = load_window(data_files, data_gen_config.size, num_candidates) + print("candidates have", [f"{p.n_rows:,}" for p in pools], "rows.") - print("Tournament results:") - for idx, _, perf in sorted(results, key=lambda t: t[2].rate(), reverse=True): - print( - f"\tcandidate {idx:03d} {perf} {perf.rate() * 100.0:.2f}% {training_configs[idx]}" - ) + fresh = list(games.head_to_head()) + random.shuffle(fresh) + for a, b, score in fresh: + update_elo(candidates[a], candidates[b], score, data_gen_config.k) + candidates[a].rated_games += 1 + candidates[b].rated_games += 1 - # 4. write champ - idx, champ, perf = max(results, key=lambda t: t[2].rate()) - path = root / "include" / f"weights_{data_gen.size}.c" - champ.to_c( - size=data_gen.size, - id=None, + total_rated_games = sum(c.rated_games for c in candidates) + print( + f"Tournament standings ({total_rated_games:,} rated games, {total_rated_games / len(candidates):,} games/candidate):" + ) + for idx, cand in sorted( + enumerate(candidates), key=lambda t: t[1].elo, reverse=True + ): + print(f"\tcandidate {idx:03d}: Elo {cand.elo:4.1f} Config {cand}") + + # 4. write champ, unconditionally + idx, champ = max(enumerate(candidates), key=lambda t: t[1].elo) + path = data_gen_config.root / "include" / f"weights_{data_gen_config.size}.c" + champ.net.to_c( + size=data_gen_config.size, + ident=None, path=path, - note=f"{iter=}, perf={str(perf)}, rate={perf.rate() * 100.0:.3f}", + note=f"{iter=}, elo={champ.elo:.1f}, rated_games={champ.rated_games:,}", + ) + _ = subprocess.run( + ["make", "clean"], cwd=data_gen_config.root, check=True, capture_output=True ) - _ = subprocess.run(["make", "clean"], cwd=root, check=True, capture_output=True) - _ = subprocess.run(["make", "native"], cwd=root, check=True, capture_output=True) - print(f"Wrote candidate {idx:03d} to {str(path)}") + _ = subprocess.run( + ["make", "native"], cwd=data_gen_config.root, check=True, capture_output=True + ) + print(f"Wrote candidate {idx:03d} to {path!s}") # 5. fine-tune on the hybrid targets -> candidate for idx, cand in enumerate(candidates): - corr, mse = cand.fit(records=records.index(idx), config=training_configs[idx]) - cand.to_c( - size=data_gen.size, - id=idx, - path=root / "include" / f"cand_{idx}_weights_{data_gen.size}.c", + corr, mse = cand.fit(pools[idx]) + cand.net.to_c( + size=data_gen_config.size, + ident=idx, + path=data_gen_config.root + / "include" + / f"cand_{idx}_weights_{data_gen_config.size}.c", note=f"id={idx}, v{iter:03d}, val_corr={corr:.4f}, val_mse={mse:.4f}", ) @@ -734,9 +817,25 @@ def main() -> None: default=8, help="length of random opening in games", ) + _ = p.add_argument( + "--train-all-games", + action="store_true", + help="train on all selfplay games, including matches between " + "different candidates (default: self vs self games only)", + ) + _ = p.add_argument( + "--k-factor", + type=float, + default=32.0, + help="elo k-factor", + ) args = p.parse_args() + # avoid counter-play start + if args.min_ply < 2: + _ = p.error("--min-ply must be >= 2") + if args.procs is None: args.procs = max(1, (os.cpu_count() or 1)) @@ -747,6 +846,9 @@ def main() -> None: games=args.games, procs=args.procs, replay_iters=args.replay_iters, + root=root, + train_only_self_play=not args.train_all_games, + k=args.k_factor, ) tgsc = TrainingGridSearchConfig( smooth_factor=args.smooth_factor, @@ -756,23 +858,20 @@ def main() -> None: val_frac=args.val_frac, ) - training_configs = tgsc.make_configs() + candidates = tgsc.make_configs(data_gen) (root / "data").mkdir(exist_ok=True) - candidates = setup( - num_candidates=len(training_configs), data_gen=data_gen, root=root - ) - num_params = sum(p.numel() for p in candidates[0].parameters() if p.requires_grad) + num_params = sum( + p.numel() for p in candidates[0].net.parameters() if p.requires_grad + ) print(f"Number of trainable parameters: {num_params:,}") for iter in range(1, args.iters + 1): run_step( candidates=candidates, - data_gen=data_gen, + data_gen_config=data_gen, iter=iter, - root=root, - training_configs=training_configs, ) print(f"\n== done, champion in include/weights_{args.size}.c ==") diff --git a/src/selfplay.c b/src/selfplay.c index b2a5821..37f94fa 100644 --- a/src/selfplay.c +++ b/src/selfplay.c @@ -169,7 +169,8 @@ static int play_game(const uint8_t min_ply, const nn_function fn_1, // final outcome of the played game, from black's perspective const int8_t R = win_value(state->won); - fprintf(stdout, "{\"result\":%d,\"rows\":[", R); + fprintf(stdout, "{\"result\":%d,\"cand_A\":%u,\"cand_B\":%u,\"rows\":[", R, + CAND_A, CAND_B); for (uint32_t k = 0; k < n_rows; k++) { fprintf(stdout, "%s{\"cand\":%u,\"root\":{\"parity\":%d,", k ? "," : "", row_cand_id[k], row_mover_sign[k]); @@ -188,8 +189,8 @@ const char *usage = "selfplay, one game of training data between candidates.\n\n\ Usage: selfplay \n\n\ Plays a single game of x, with moves made randomly. Only the deterministic plies are written to stdout, one JSON record per game, from ply onwards:\n\n\ -\t{\"result\": R, \"rows\": [{\"cand\": id, \"root\": {\"parity\", \"head\", \"cells\"}, \"leaf\": {\"parity\", \"head\", \"cells\", \"terminal\", \"terminal_value\"}}]}\n\n\ -R is the outcome of the game from black's perspective. Each row records the net input of the root state s_t and the PV leaf selected at that ply; the leaf value Net(pv) is taken from the trained net. nn_train.py runs many of these in parallel to generate training data.\n\n\ +\t{\"result\": R, \"cand_A\": i, \"cand_B\": j, \"rows\": [{\"cand\": id, \"root\": {\"parity\", \"head\", \"cells\"}, \"leaf\": {\"parity\", \"head\", \"cells\", \"terminal\", \"terminal_value\"}}]}\n\n\ +R is the outcome of the game from black's perspective; cand_A and cand_B are the ids of the two candidates that played the game. Each row records the net input of the root state s_t and the PV leaf selected at that ply; the leaf value Net(pv) is taken from the trained net. nn_train.py runs many of these in parallel to generate training data.\n\n\ Copyright (C) 2026, tslil clingman\n\n\ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version."; -- cgit v1.3.1