Spaces:
Running on Zero
Running on Zero
Add selective input, layer and output freezing
Browse files- .gitattributes +1 -0
- BINARY_PROVENANCE.json +55 -1
- FRONTEND_SOURCE.json +23 -1
- RELEASE_MANIFEST.json +93 -1
- UPSTREAM.json +21 -1
- bin/altd-sim +2 -2
- bucket_storage.py +5 -2
- build_info.py +1 -1
- client.js +20 -6
- help.html +6 -1
- index.html +34 -4
- native/selective-freeze-build-receipt.json +38 -0
- native/selective-freeze-source.tar.gz +3 -0
- portable_bundle.py +20 -3
- training_config.py +18 -2
- worker.py +44 -0
.gitattributes
CHANGED
|
@@ -1 +1,2 @@
|
|
| 1 |
bin/* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 1 |
bin/* filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
native/selective-freeze-source.tar.gz filter=lfs diff=lfs merge=lfs -text
|
BINARY_PROVENANCE.json
CHANGED
|
@@ -1 +1,55 @@
|
|
| 1 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"artifacts": {
|
| 3 |
+
"bin/altd-sim": {
|
| 4 |
+
"bytes": 3647808,
|
| 5 |
+
"sha256": "ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070"
|
| 6 |
+
},
|
| 7 |
+
"bin/extract_saved_track": {
|
| 8 |
+
"bytes": 3247776,
|
| 9 |
+
"sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a"
|
| 10 |
+
},
|
| 11 |
+
"bin/libaltd_gpu.so": {
|
| 12 |
+
"bytes": 4711704,
|
| 13 |
+
"sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca"
|
| 14 |
+
}
|
| 15 |
+
},
|
| 16 |
+
"build_receipt_path": "native/selective-freeze-build-receipt.json",
|
| 17 |
+
"build_receipt_sha256": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
|
| 18 |
+
"compiler": "rustc 1.95.0 aarch64-apple-darwin -> x86_64-unknown-linux-gnu",
|
| 19 |
+
"historical_native_files": [
|
| 20 |
+
"native/analysis.patch",
|
| 21 |
+
"native/build-receipt.json",
|
| 22 |
+
"native/source-receipt.json"
|
| 23 |
+
],
|
| 24 |
+
"linux_runtime_status": "hosted execution pending",
|
| 25 |
+
"retained_artifact_origins": {
|
| 26 |
+
"bin/extract_saved_track": {
|
| 27 |
+
"build_receipt_path": "IMPORTER_BUILD_RECEIPT.json",
|
| 28 |
+
"build_receipt_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 29 |
+
"bytes": 3247776,
|
| 30 |
+
"compatibility_receipt_path": "native/build-receipt.json",
|
| 31 |
+
"compatibility_receipt_sha256": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
|
| 32 |
+
"evidence_path": "IMPORTER_BUILD_RECEIPT.json",
|
| 33 |
+
"evidence_sha256": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 34 |
+
"origin_type": "retained_verified_importer_binary",
|
| 35 |
+
"sha256": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
|
| 36 |
+
"source_repository": "https://github.com/Zorro909/driving_sim_rs",
|
| 37 |
+
"source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f"
|
| 38 |
+
},
|
| 39 |
+
"bin/libaltd_gpu.so": {
|
| 40 |
+
"build_receipt_path": "native/build-receipt.json",
|
| 41 |
+
"build_receipt_sha256": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
|
| 42 |
+
"bytes": 4711704,
|
| 43 |
+
"origin_type": "retained_cuda_b90",
|
| 44 |
+
"patch_sha256": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
|
| 45 |
+
"sha256": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca",
|
| 46 |
+
"source_receipt_sha256": "36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93",
|
| 47 |
+
"source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
|
| 48 |
+
}
|
| 49 |
+
},
|
| 50 |
+
"schema": "ald-selective-freeze-binary-provenance-v1",
|
| 51 |
+
"source_base_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
|
| 52 |
+
"source_repository": "https://github.com/Zorro909/driving_sim_rs",
|
| 53 |
+
"source_snapshot_path": "native/selective-freeze-source.tar.gz",
|
| 54 |
+
"source_snapshot_sha256": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db"
|
| 55 |
+
}
|
FRONTEND_SOURCE.json
CHANGED
|
@@ -1 +1,23 @@
|
|
| 1 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"base_provenance": {
|
| 3 |
+
"output_sha256": "a145fbb303a85c728a530d98fbea998677c1c62a2589c46af9b8b287e4ce1f48",
|
| 4 |
+
"scope": "Frontend only; no engine, private data, track assets, API calls or storage copied",
|
| 5 |
+
"source": "Runner r14 single-engine browser UI; selected .track tile renderer added from simulator atlas",
|
| 6 |
+
"source_sha256": "65d1e5f2c4e19b4951b828e82510005ab99a5270cf3dcb9f4eaa0fa1af8c40f8"
|
| 7 |
+
},
|
| 8 |
+
"client_sha256": "420c2a22814525083eab0bc9865ad705c48a75bdffe7bdc4f2b85d3837fbe8e4",
|
| 9 |
+
"identity_note": "The historical source fields describe the base frontend; local packaged file hashes describe this candidate's derived frontend.",
|
| 10 |
+
"local_customization_id": "v1.2-selective-freezing",
|
| 11 |
+
"output_sha256": "063dcbd45ee0528768b634be6bb2637622a68524dc1077ab4e1599a4776a3111",
|
| 12 |
+
"packaged_frontend_files": {
|
| 13 |
+
"assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
|
| 14 |
+
"client.js": "420c2a22814525083eab0bc9865ad705c48a75bdffe7bdc4f2b85d3837fbe8e4",
|
| 15 |
+
"help.html": "d9b1e3b87641d73d4504b54ee33fa3c7d0917ea9c9c454cc632665fd41ace950",
|
| 16 |
+
"hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
|
| 17 |
+
"index.html": "063dcbd45ee0528768b634be6bb2637622a68524dc1077ab4e1599a4776a3111",
|
| 18 |
+
"track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
|
| 19 |
+
"track-map.js": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0"
|
| 20 |
+
},
|
| 21 |
+
"packaged_frontend_sha256": "f32657b54c2633a06a8dd3051a9e8b4cdd10560c9ac5474f7e5c6c3208949706",
|
| 22 |
+
"status": "Local selective-freeze candidate; hosted qualification pending"
|
| 23 |
+
}
|
RELEASE_MANIFEST.json
CHANGED
|
@@ -1 +1,93 @@
|
|
| 1 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "gpu",
|
| 3 |
+
"files": {
|
| 4 |
+
".gitattributes": "c2ad16718fc51c888d32efc88c8f6e23ebe5fcf6f48e2954f896ba9770f24d72",
|
| 5 |
+
"BETA_TESTING.md": "829dae67ec37dac2a4e7b178ab5ee4fc5f63896af132fbff457a5e35141fe94d",
|
| 6 |
+
"BINARY_PROVENANCE.json": "e05f4c3a4a2a0da39b213708c532f3e514109c5530250b402347a8d751105052",
|
| 7 |
+
"BUCKET_BUNDLE.md": "cb7a0f023d5a1f93f0288c6a5646b64f8f3e9d36150c0730aea94590e5b80260",
|
| 8 |
+
"CUDA_REFERENCE.md": "f7453c3254d244f8b0de41fde5851cb025159f5cea4a4d1a5d8208a955550c6c",
|
| 9 |
+
"DATA_POLICY.md": "fc5978528abe1c21c14882417ac8a706e04a0831bbd3fdb3de8c64442c1a7b3d",
|
| 10 |
+
"FEEDBACK.md": "f95b8f6afbf4a360976c0edca5d52f5b3a0b668c9a944d4947b840a7c53a122a",
|
| 11 |
+
"FRONTEND_SOURCE.json": "fe24f1251ef7f6c35c121310012b718aaf13f4a409433e67f00e7f3836af7890",
|
| 12 |
+
"GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
|
| 13 |
+
"IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
|
| 14 |
+
"LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
|
| 15 |
+
"README.md": "c0fb705dff468ea502a0a810f47a450f5d2f42c0c3b0178c3b662b27a327b8a5",
|
| 16 |
+
"STORAGE_BOUNDARY.md": "1d0cab6c82723f1879d7b437bab6b0d21248436bce161f3fbfe6c0e83b9e87a1",
|
| 17 |
+
"TRACK_LIBRARY.md": "be64c91633ef6696233df537afeef4c5175b2d55daac9336758d9eb3d24763c9",
|
| 18 |
+
"UPSTREAM.json": "ad5ff9011f329d9a05b18943118ebee914373501453971f786c1ee037213a83f",
|
| 19 |
+
"WINNERS_AND_EVALUATION.md": "f281cf496763c59c50a79161cfff1a46d3529edfcfaaa14962c9a3f2d4f9446f",
|
| 20 |
+
"analysis_result.py": "0a5d73fe8dbca934b21823b8ffbd50b0baaef8e15a39e32604eefe16f01d1cf2",
|
| 21 |
+
"app.py": "78ddccd56e5c217b89681c5dcbee451b6a5868398c4f75bd2b4db33c235d800f",
|
| 22 |
+
"app_release.py": "7482559c667a665fd3cb6aa8af6c78422a822b515e14589db8306f7fd4860a8b",
|
| 23 |
+
"assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
|
| 24 |
+
"assets/rally_template.json": "7350a3fe28d9b4da7a0965ae6ea7ca3472fb7885303e342310d63a0dce80851c",
|
| 25 |
+
"assets/snowmobile_template.json": "12d30545876011fd6fccdd3e721f9c465938c9c58ac99338205481d5e7ac6742",
|
| 26 |
+
"assets/track-atlas.json": "d97c8900e3e5fb17734b5bd61d1f4f4b196d9be30af9848e2e273ae7e4079ae4",
|
| 27 |
+
"assets/truck_template.json": "a83bffea4d5e818c135ab3aba68a47aa288d6ad0e7b8bd9c95ed0dea9e9df2f7",
|
| 28 |
+
"bin/altd-sim": "ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070",
|
| 29 |
+
"bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
|
| 30 |
+
"bin/libaltd_gpu.so": "3b1b88bccc06a21acc33ac4400af016d55a7e3d8727136a0c43b541f3c7887ca",
|
| 31 |
+
"bucket_storage.py": "347ad556254aa9f255209141cf37f48c58c01134318c08b7bcd6ed2caa95e7a4",
|
| 32 |
+
"build_info.py": "2a57f73abd9e062cf029b65b09b26b8d12e301bac2f7efec7edb4b85b47671c3",
|
| 33 |
+
"builtin_tracks.py": "52cb4a285a6079cec7f7610de8af80570f1644a02cf9979e47d2d49736e24cb5",
|
| 34 |
+
"builtin_tracks/catalog.json": "4a7bba4385713e985d1427a0da35dcc32d5ecfd73d93cad7520563deb8685670",
|
| 35 |
+
"builtin_tracks/tracks/Replica A01 Beginner.track": "ca5749537450430794e2eade2e0ac72fa141a4f225e13e2f8ef842abb948ff15",
|
| 36 |
+
"builtin_tracks/tracks/Replica A02 Sharp Turns.track": "097f1ea8edf041112b690d0638075630716ddc03c7d0b1980ddcbeaf5071c8d4",
|
| 37 |
+
"builtin_tracks/tracks/Replica A03 High Speed.track": "88917c63847be1854b989bb28a23af7eeacb964c3e7df9579953aebc9496e6af",
|
| 38 |
+
"builtin_tracks/tracks/Replica A04 Dirt.track": "7f4fe58516227b15898d14bb0abb9a0856126d24fcd793884f051f7a4fae521d",
|
| 39 |
+
"builtin_tracks/tracks/Replica A05 Two Terrains.track": "c4ee2842920d99cdfe3eebdcad59a77e24b626380acef0d02a39ea1e23823e2a",
|
| 40 |
+
"builtin_tracks/tracks/Replica A06 Ice.track": "fccb9a159a06d1b986c6fe7d5bb89c0cabad3a005531f4e0d71f6e37254ada34",
|
| 41 |
+
"builtin_tracks/tracks/Replica A07 Three Terrains.track": "a8fa652ad451e2702a23d5f3429eb0b6a6408bf6a2a76a73d549023e481875c6",
|
| 42 |
+
"builtin_tracks/tracks/Replica A08 Long.track": "3e259bd227776ca847d35baaea88b5e8af57cc920643bf71563176bd6554ad65",
|
| 43 |
+
"builtin_tracks/tracks/Replica A09 Sharpest.track": "5362cea3c564dce8f4f22fcd4b798347931dfaa4e65b84624944952b3e0b0d2a",
|
| 44 |
+
"builtin_tracks/tracks/Replica B01 Oval.track": "0df5755150c145a35edc6c8693f429e5b9ff4b12210ba67cbfcb932c58faf158",
|
| 45 |
+
"builtin_tracks/tracks/Replica B02 Snake.track": "210e699b1fa5f2624a2ff0969b73a20af7bc56bf774f4fd282f6109f80bfdb3c",
|
| 46 |
+
"builtin_tracks/tracks/Replica B03 Slalom.track": "a8bab86f93e3072bf27a81a354220c137207b9fc0b548372c8dab93639a18a24",
|
| 47 |
+
"builtin_tracks/tracks/Replica B04 Rally.track": "9d2fc668a7c86aabb9ca9dbfdbd21dff0d099c5d77029aa2ae96b6c7b9efd3f0",
|
| 48 |
+
"builtin_tracks/tracks/Replica B05 Racetrack.track": "d0804ebc17646d2f7c3be65cfe0f6e94033417e75b101a8c598a69131a170079",
|
| 49 |
+
"builtin_tracks/tracks/Replica B06 Hard.track": "8b1a10fd8485405d7f73abca8890f4845145227177c9ac07ac9a1d79f28908f9",
|
| 50 |
+
"builtin_tracks/tracks/Replica B07 Drift.track": "d6d46216882cb63d55b1e8ce81ffa67f1c95ffd0a86a72806b8fd23973c6ce0a",
|
| 51 |
+
"builtin_tracks/tracks/Replica B08 Arctic Circle.track": "229128e86a87089f781b072a4c677ff729cf8488b1d74ad75cfb43655b9f4a16",
|
| 52 |
+
"builtin_tracks/tracks/Replica B09 Checkered.track": "bec4dbd0edc35e0e4f4d1035c608a0c56bbc99e7301f640f8e2eddba0100b2fe",
|
| 53 |
+
"builtin_tracks/tracks/Replica R01 Blitzring.track": "14b52a7cbbf7de5606c772c74730c0e8776f39ed72955fef5ae1f7c2d8ccef77",
|
| 54 |
+
"builtin_tracks/tracks/Replica R02 Desert Rally.track": "653286b00f2f04450e698d8b8e9d4ecb268064b323b182d2de9db7d017b22238",
|
| 55 |
+
"builtin_tracks/tracks/Replica R03 Glacier.track": "0e1b42ce51ae91a8702e173013a090d00145e518bb47d7a659cb1d1fdff011b5",
|
| 56 |
+
"builtin_tracks/tracks/Replica R04 Truck Maze.track": "d7b89d64e118506e6cec259057886d9267ca4c6fab570e7ba0d6641e8f822f11",
|
| 57 |
+
"builtin_tracks/tracks/Replica R05 Endurance 500.track": "dde36ad5f627bce65d45a96d46a68497f8d446f6011c9df19ee51ce71375cba8",
|
| 58 |
+
"builtin_tracks/tracks/Replica R06 Mix.track": "9de8d912a59001ea13baa7f1b4f92884b8cddf91978f31e19f3237975713f739",
|
| 59 |
+
"builtin_tracks/tracks/Replica R07 Mirage Marina.track": "8c6764f3accb1a8372d910d57f4f681572dd40c590c4a3d03517379bb360fcd7",
|
| 60 |
+
"builtin_tracks/tracks/Replica R08 Demolition Derby.track": "6f11a9ffbcb477c9d19964566b1b612d2a94675605246e93e21f27bbbdb357ef",
|
| 61 |
+
"builtin_tracks/tracks/Replica R09 Eau Noir.track": "3ec0a78478cca1a4f0d2d98ac81f40783928adf271b70f0c32d295a6da2cdaa9",
|
| 62 |
+
"builtin_tracks/tracks/Replica The Champions Trial.track": "a3bfb76422affc774b44c739b0636d08acb901fa7615b9adcb52c069f79834e1",
|
| 63 |
+
"client.js": "420c2a22814525083eab0bc9865ad705c48a75bdffe7bdc4f2b85d3837fbe8e4",
|
| 64 |
+
"delivery.py": "6bdba2e87c3e19a41440cb16103695af27105f8bafbae38948bbb1b936ed0c1b",
|
| 65 |
+
"gpu_tickets.py": "b81aadb5ed42cec9212d44da7e7bbb7b413c5bd517383cac0b49ec9b4d659c92",
|
| 66 |
+
"help.html": "d9b1e3b87641d73d4504b54ee33fa3c7d0917ea9c9c454cc632665fd41ace950",
|
| 67 |
+
"hf-auth.js": "3f3938bbc0935e4e9230c094029ef46e03beea74be199887c50e053e03dafcfe",
|
| 68 |
+
"hf_identity.py": "913fb1e089af21f376e8359a20cbc838d5bcd7971def6989a4382d53c1127b37",
|
| 69 |
+
"index.html": "063dcbd45ee0528768b634be6bb2637622a68524dc1077ab4e1599a4776a3111",
|
| 70 |
+
"native/analysis.patch": "42f79de67cb0734cffb2a7582f5479cab42ab82675884b8b42b9f158d46a98e8",
|
| 71 |
+
"native/build-receipt.json": "559a7e4e382f9f7caa1c5ceb566a5a0bbefad2ed3a2e2cf604e31c9c3890c348",
|
| 72 |
+
"native/selective-freeze-build-receipt.json": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
|
| 73 |
+
"native/selective-freeze-source.tar.gz": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db",
|
| 74 |
+
"native/source-receipt.json": "36feba861501baf8672884476bbeed5e375254cbb4feffb9f4f90aa61a415a93",
|
| 75 |
+
"portable_bundle.py": "b32ca0b8d79f13230fde6e914769e0af71cd44ef950d798da83499878ab28e15",
|
| 76 |
+
"requirements.txt": "fc7e0703ad2289fd3926a36efbdce8c61f0edc00f7575a87e2b565e46588c5a4",
|
| 77 |
+
"server.py": "1f82c9046324661d7bd4acf1cf37eef3445f985351159d88acdcaf89d1edf859",
|
| 78 |
+
"star_check.py": "61d35bcede5dab75911b2734ff20cb38f7a06bde9fd58c2eff67f5833b260d40",
|
| 79 |
+
"steam_leaderboard.py": "d76397c39cae58f636ddf9a9be1a46ae3d77fefd6b7269feac73d34d97165481",
|
| 80 |
+
"track-library.js": "351ec4c026b49420ce963f4310cb000d9e987fd28e6dac5ecd0176509340f6e6",
|
| 81 |
+
"track-map.js": "ab5374aa49c7ccec90a787ee8c56cd71beb56b903bf2bbc322783e6f43c009f0",
|
| 82 |
+
"training_config.py": "59141f96e47aba5bc91e8a08d0f40384ea8c90ea0b3e5a12ad65abdad3987a8d",
|
| 83 |
+
"vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
|
| 84 |
+
"vendor/gradio-client/dist/index.min.js": "fdd776db8633354f118fe2908c980592283968737e6b91dc3aa86d648da5c3fd",
|
| 85 |
+
"vendor/gradio-client/package.json": "96c5b9e6d3587fb7bd8e5bb28775ece222de1043045afc4e6389c88db137ad0e",
|
| 86 |
+
"vendor/hf-oauth/LICENSE": "d6e7b19451c1b3d1d66353bb4b1274138953b3bfd9ae60c56e77b1f548796982",
|
| 87 |
+
"vendor/hf-oauth/index.js": "53282844000a171011e547f6472a3846bb4cecb5071adafea079fcac3a2aee7e",
|
| 88 |
+
"vendor/hf-oauth/package.json": "fafd4d8891023a1961546a7d3bc25cd24f64923a2ebfc449fe6d516a2949bda8",
|
| 89 |
+
"worker.py": "ebfb82560c721936520bb601e117dc697bb6a046a2fc4ef4207a80250dba917b"
|
| 90 |
+
},
|
| 91 |
+
"interface": "single-engine-runner-with-map-winners-analysis-v1",
|
| 92 |
+
"upstream_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0"
|
| 93 |
+
}
|
UPSTREAM.json
CHANGED
|
@@ -1 +1,21 @@
|
|
| 1 |
-
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"commit": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
|
| 3 |
+
"importer_source_revision": "d8ab74c25df70b6a86ed101080e33d5fb785ea6f",
|
| 4 |
+
"math_profile": "proton",
|
| 5 |
+
"native_build": {
|
| 6 |
+
"build_receipt_path": "native/selective-freeze-build-receipt.json",
|
| 7 |
+
"build_receipt_sha256": "ed804b1cd49a9ba34abc6f7cadaf4fb97807e27f3d14af117f8292a2d3f2d172",
|
| 8 |
+
"cuda_library_origin": "retained CUDA library from prior hosted build; device check pending",
|
| 9 |
+
"simulator_origin": "locally cross-compiled Linux executable with selective freezing",
|
| 10 |
+
"source_revision": "b90b8af06ffc4ea4e4fd703becd1107a48b8e5e0",
|
| 11 |
+
"source_snapshot_path": "native/selective-freeze-source.tar.gz",
|
| 12 |
+
"source_snapshot_sha256": "297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db"
|
| 13 |
+
},
|
| 14 |
+
"open_prs_not_included": [
|
| 15 |
+
19,
|
| 16 |
+
21
|
| 17 |
+
],
|
| 18 |
+
"repository": "https://github.com/Zorro909/driving_sim_rs",
|
| 19 |
+
"role": "gpu",
|
| 20 |
+
"ui_refresh_date": "2026-10-12"
|
| 21 |
+
}
|
bin/altd-sim
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070
|
| 3 |
+
size 3647808
|
bucket_storage.py
CHANGED
|
@@ -17,7 +17,7 @@ import uuid
|
|
| 17 |
|
| 18 |
from portable_bundle import (
|
| 19 |
BundleError, MAX_BUNDLE, MAX_NETWORK, MAX_ANALYSIS_ARCHIVE,
|
| 20 |
-
MAX_ANALYSIS_FILE_BYTES, load_bundle,
|
| 21 |
)
|
| 22 |
from worker import network_input
|
| 23 |
|
|
@@ -124,8 +124,11 @@ def validate_recipe_library(raw: bytes) -> dict:
|
|
| 124 |
raise ValueError("Invalid recipe library")
|
| 125 |
seen.add(slot)
|
| 126 |
settings = recipe["settings"]
|
| 127 |
-
if not isinstance(settings, dict)
|
|
|
|
| 128 |
raise ValueError("Invalid recipe library")
|
|
|
|
|
|
|
| 129 |
clean = {**RECIPE_DEFAULT_SETTINGS, **settings}
|
| 130 |
numeric = {
|
| 131 |
"population": (1, 128, True), "generations": (1, 1000, True),
|
|
|
|
| 17 |
|
| 18 |
from portable_bundle import (
|
| 19 |
BundleError, MAX_BUNDLE, MAX_NETWORK, MAX_ANALYSIS_ARCHIVE,
|
| 20 |
+
MAX_ANALYSIS_FILE_BYTES, load_bundle, validate_freeze,
|
| 21 |
)
|
| 22 |
from worker import network_input
|
| 23 |
|
|
|
|
| 124 |
raise ValueError("Invalid recipe library")
|
| 125 |
seen.add(slot)
|
| 126 |
settings = recipe["settings"]
|
| 127 |
+
if (not isinstance(settings, dict)
|
| 128 |
+
or set(settings) - (set(RECIPE_DEFAULT_SETTINGS) | {"freeze"})):
|
| 129 |
raise ValueError("Invalid recipe library")
|
| 130 |
+
if "freeze" in settings:
|
| 131 |
+
validate_freeze(settings["freeze"])
|
| 132 |
clean = {**RECIPE_DEFAULT_SETTINGS, **settings}
|
| 133 |
numeric = {
|
| 134 |
"population": (1, 128, True), "generations": (1, 1000, True),
|
build_info.py
CHANGED
|
@@ -19,6 +19,6 @@ def build_identity():
|
|
| 19 |
"package_role": 'gpu',
|
| 20 |
"binary_sha256": {name: digest for name, digest in manifest["files"].items() if name.startswith("bin/")},
|
| 21 |
"native_source_revision": native["source_revision"],
|
| 22 |
-
"
|
| 23 |
"native_build_receipt_sha256": native["build_receipt_sha256"],
|
| 24 |
}
|
|
|
|
| 19 |
"package_role": 'gpu',
|
| 20 |
"binary_sha256": {name: digest for name, digest in manifest["files"].items() if name.startswith("bin/")},
|
| 21 |
"native_source_revision": native["source_revision"],
|
| 22 |
+
"native_source_snapshot_sha256": native["source_snapshot_sha256"],
|
| 23 |
"native_build_receipt_sha256": native["build_receipt_sha256"],
|
| 24 |
}
|
client.js
CHANGED
|
@@ -108,6 +108,7 @@ function syncRunModeUI(unavailable=busy||!!job||bundleRestoring||bucketOperation
|
|
| 108 |
for(const id of trainingOnlyControls){const node=$(id);if(node)node.disabled=unavailable||evaluation;}
|
| 109 |
if($('native_settings'))$('native_settings').hidden=evaluation;
|
| 110 |
if($('reward_settings'))$('reward_settings').hidden=evaluation;
|
|
|
|
| 111 |
if($('run'))$('run').textContent=evaluation?'Evaluate policy (weights frozen)':'Run training';
|
| 112 |
if($('run_mode_help'))$('run_mode_help').textContent=evaluation
|
| 113 |
?'Frozen evaluation uses the selected policy unchanged in a fresh car. Mutation, decay, crossover, reproduction and winner selection are disabled.'
|
|
@@ -433,7 +434,12 @@ async function encoded(file) {
|
|
| 433 |
}
|
| 434 |
const headers = () => ({'X-Job-Key':job.key});
|
| 435 |
const networkSource=()=>stagedNetwork || $('network').files[0];
|
| 436 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 437 |
window.TrainingClient={
|
| 438 |
isBusy:()=>busy||!!job||bundleRestoring,
|
| 439 |
hasUnsavedState:()=>!!(networkSource()||localResult||$('track').files.length||trackLibrary?.info?.()?.source==='builtin'||$('editor_file')?.files.length||window.hasUnsavedNetworkDraft?.()),
|
|
@@ -441,6 +447,7 @@ window.TrainingClient={
|
|
| 441 |
if(busy||job)throw Error('Finish or delete the current result before changing the network');
|
| 442 |
stagedNetwork=file;$('network').value='';
|
| 443 |
if($('networkChoice'))$('networkChoice').textContent='Browser editor input: '+file.name+'. Not uploaded yet.';
|
|
|
|
| 444 |
buttons();
|
| 445 |
}
|
| 446 |
};
|
|
@@ -931,7 +938,7 @@ $('run').onclick = async () => {
|
|
| 931 |
if($('leaderboard_opt_in')?.checked)void checkSteamLeaderboard(trackInfo,r);
|
| 932 |
else if($('leaderboard_status'))$('leaderboard_status').textContent='';
|
| 933 |
if(!comparisonPlan)$('track').value=''; $('network').value='';
|
| 934 |
-
stagedNetwork=null;if($('networkChoice'))$('networkChoice').textContent='Network input released after the run.';
|
| 935 |
say('Result ready ('+job.backend.toUpperCase()+'). Inputs and intermediate worker files have been removed.');
|
| 936 |
if(autosaveSnapshot){
|
| 937 |
try{
|
|
@@ -1178,6 +1185,12 @@ const bundleMessage=text=>{if($('bundle_status'))$('bundle_status').textContent=
|
|
| 1178 |
const bundleExact=(value,keys)=>{
|
| 1179 |
if(!value||typeof value!=='object'||Array.isArray(value)||Object.keys(value).sort().join()!==[...keys].sort().join())throw Error('Unexpected receipt fields');
|
| 1180 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1181 |
const bundleFinite=value=>typeof value==='number'&&Number.isFinite(value);
|
| 1182 |
const runHistoryKeys=['generation','mutation','best_score','mean_score','best_lap_seconds','lapped_cars','simulated_ticks'];
|
| 1183 |
function cleanRunHistory(value){
|
|
@@ -1210,7 +1223,7 @@ function cleanRunReceipt(source){
|
|
| 1210 |
bundleExact(report.inputs,['track_sha256','network_sha256']);
|
| 1211 |
if(!/^[a-f0-9]{64}$/.test(report.inputs.track_sha256)||!/^[a-f0-9]{64}$/.test(report.inputs.network_sha256))return null;
|
| 1212 |
const recipeSettings={...report.settings},sourceMode=recipeSettings.mode,sourceCleanMinLaps=recipeSettings.clean_min_laps;delete recipeSettings.mode;delete recipeSettings.clean_min_laps;
|
| 1213 |
-
|
| 1214 |
const analysisSummary=report.analysis_summary?validateAnalysisSummary(report.analysis_summary):null,mode=analysisSummary?.mode??sourceMode;
|
| 1215 |
const cleanMinLaps=analysisSummary?.conditions.clean_min_laps??sourceCleanMinLaps??2;
|
| 1216 |
if((sourceMode!==undefined&&!['train','evaluate'].includes(sourceMode))||(analysisSummary&&sourceMode!==undefined&&sourceMode!==analysisSummary.mode)||
|
|
@@ -1219,9 +1232,10 @@ function cleanRunReceipt(source){
|
|
| 1219 |
let settings;
|
| 1220 |
if(mode==='evaluate'){
|
| 1221 |
if(recipeSettings.population!==1||recipeSettings.generations!==1||recipeSettings.mutation!==0||recipeSettings.mutation_end!==0||recipeSettings.schedule!=='fixed'||recipeSettings.selection!=='best'||recipeSettings.parents!==1||recipeSettings.elite!==0||recipeSettings.crossover!=='none'||recipeSettings.decay!==0||recipeSettings.adaptive_mutation!==false)return null;
|
| 1222 |
-
const checked=window.RecipeLibrary.settings({...
|
| 1223 |
settings={...checked,mutation:0,mutation_end:0};
|
| 1224 |
-
}else settings=
|
|
|
|
| 1225 |
const history=cleanRunHistory(report.history);
|
| 1226 |
settings.mode=mode??'train';settings.clean_min_laps=cleanMinLaps;
|
| 1227 |
if(report.population!==settings.population||report.generations_requested!==settings.generations||report.requested_ticks!==settings.ticks||(history&&history.length!==report.generations_completed))return null;
|
|
@@ -1374,7 +1388,7 @@ async function preparePortableText(text){
|
|
| 1374 |
}
|
| 1375 |
parsed.track.file=await validateBundleTrack(parsed.track);
|
| 1376 |
}
|
| 1377 |
-
if(parsed.recipe)
|
| 1378 |
if(parsed.receipt){
|
| 1379 |
if(parsed.analysis){
|
| 1380 |
const clean=cleanRunReceipt(parsed.receipt);if(!clean)throw Error('Run receipt failed its allowlist or value checks');
|
|
|
|
| 108 |
for(const id of trainingOnlyControls){const node=$(id);if(node)node.disabled=unavailable||evaluation;}
|
| 109 |
if($('native_settings'))$('native_settings').hidden=evaluation;
|
| 110 |
if($('reward_settings'))$('reward_settings').hidden=evaluation;
|
| 111 |
+
if($('freeze_settings'))$('freeze_settings').hidden=evaluation;
|
| 112 |
if($('run'))$('run').textContent=evaluation?'Evaluate policy (weights frozen)':'Run training';
|
| 113 |
if($('run_mode_help'))$('run_mode_help').textContent=evaluation
|
| 114 |
?'Frozen evaluation uses the selected policy unchanged in a fresh car. Mutation, decay, crossover, reproduction and winner selection are disabled.'
|
|
|
|
| 434 |
}
|
| 435 |
const headers = () => ({'X-Job-Key':job.key});
|
| 436 |
const networkSource=()=>stagedNetwork || $('network').files[0];
|
| 437 |
+
async function refreshFreezeNetwork(file){
|
| 438 |
+
if(!file){window.setFreezeNetwork?.(null);return;}
|
| 439 |
+
try{const network=await validateNetworkBytes(new Uint8Array(await file.arrayBuffer()));if(networkSource()===file)window.setFreezeNetwork?.(network);}
|
| 440 |
+
catch(error){if(networkSource()===file){window.setFreezeNetwork?.(null);if($('freeze_status'))$('freeze_status').textContent='Network metadata unavailable: '+error.message;}}
|
| 441 |
+
}
|
| 442 |
+
$('network').onchange=()=>{stagedNetwork=null;selectedWinner=null;if($('networkChoice'))$('networkChoice').textContent='Uploaded file selected.';refreshFreezeNetwork(networkSource());buttons();};
|
| 443 |
window.TrainingClient={
|
| 444 |
isBusy:()=>busy||!!job||bundleRestoring,
|
| 445 |
hasUnsavedState:()=>!!(networkSource()||localResult||$('track').files.length||trackLibrary?.info?.()?.source==='builtin'||$('editor_file')?.files.length||window.hasUnsavedNetworkDraft?.()),
|
|
|
|
| 447 |
if(busy||job)throw Error('Finish or delete the current result before changing the network');
|
| 448 |
stagedNetwork=file;$('network').value='';
|
| 449 |
if($('networkChoice'))$('networkChoice').textContent='Browser editor input: '+file.name+'. Not uploaded yet.';
|
| 450 |
+
refreshFreezeNetwork(file);
|
| 451 |
buttons();
|
| 452 |
}
|
| 453 |
};
|
|
|
|
| 938 |
if($('leaderboard_opt_in')?.checked)void checkSteamLeaderboard(trackInfo,r);
|
| 939 |
else if($('leaderboard_status'))$('leaderboard_status').textContent='';
|
| 940 |
if(!comparisonPlan)$('track').value=''; $('network').value='';
|
| 941 |
+
stagedNetwork=null;window.setFreezeNetwork?.(null);if($('networkChoice'))$('networkChoice').textContent='Network input released after the run.';
|
| 942 |
say('Result ready ('+job.backend.toUpperCase()+'). Inputs and intermediate worker files have been removed.');
|
| 943 |
if(autosaveSnapshot){
|
| 944 |
try{
|
|
|
|
| 1185 |
const bundleExact=(value,keys)=>{
|
| 1186 |
if(!value||typeof value!=='object'||Array.isArray(value)||Object.keys(value).sort().join()!==[...keys].sort().join())throw Error('Unexpected receipt fields');
|
| 1187 |
};
|
| 1188 |
+
const bundleSettings=value=>{
|
| 1189 |
+
const currentKeys=Object.keys(window.RecipeLibrary.defaults),legacyKeys=currentKeys.filter(key=>key!=='freeze');
|
| 1190 |
+
const keys=Object.keys(value||{}).sort().join();
|
| 1191 |
+
if(keys!==[...currentKeys].sort().join()&&keys!==legacyKeys.sort().join())throw Error('Unexpected recipe settings fields');
|
| 1192 |
+
return window.RecipeLibrary.settings(value);
|
| 1193 |
+
};
|
| 1194 |
const bundleFinite=value=>typeof value==='number'&&Number.isFinite(value);
|
| 1195 |
const runHistoryKeys=['generation','mutation','best_score','mean_score','best_lap_seconds','lapped_cars','simulated_ticks'];
|
| 1196 |
function cleanRunHistory(value){
|
|
|
|
| 1223 |
bundleExact(report.inputs,['track_sha256','network_sha256']);
|
| 1224 |
if(!/^[a-f0-9]{64}$/.test(report.inputs.track_sha256)||!/^[a-f0-9]{64}$/.test(report.inputs.network_sha256))return null;
|
| 1225 |
const recipeSettings={...report.settings},sourceMode=recipeSettings.mode,sourceCleanMinLaps=recipeSettings.clean_min_laps;delete recipeSettings.mode;delete recipeSettings.clean_min_laps;
|
| 1226 |
+
const normalizedSettings=bundleSettings(recipeSettings);
|
| 1227 |
const analysisSummary=report.analysis_summary?validateAnalysisSummary(report.analysis_summary):null,mode=analysisSummary?.mode??sourceMode;
|
| 1228 |
const cleanMinLaps=analysisSummary?.conditions.clean_min_laps??sourceCleanMinLaps??2;
|
| 1229 |
if((sourceMode!==undefined&&!['train','evaluate'].includes(sourceMode))||(analysisSummary&&sourceMode!==undefined&&sourceMode!==analysisSummary.mode)||
|
|
|
|
| 1232 |
let settings;
|
| 1233 |
if(mode==='evaluate'){
|
| 1234 |
if(recipeSettings.population!==1||recipeSettings.generations!==1||recipeSettings.mutation!==0||recipeSettings.mutation_end!==0||recipeSettings.schedule!=='fixed'||recipeSettings.selection!=='best'||recipeSettings.parents!==1||recipeSettings.elite!==0||recipeSettings.crossover!=='none'||recipeSettings.decay!==0||recipeSettings.adaptive_mutation!==false)return null;
|
| 1235 |
+
const checked=window.RecipeLibrary.settings({...normalizedSettings,mutation:0.01,mutation_end:0.01});
|
| 1236 |
settings={...checked,mutation:0,mutation_end:0};
|
| 1237 |
+
}else settings=normalizedSettings;
|
| 1238 |
+
if(mode==='evaluate'&&(settings.freeze.layers.length||settings.freeze.inputs.length||settings.freeze.outputs.length))return null;
|
| 1239 |
const history=cleanRunHistory(report.history);
|
| 1240 |
settings.mode=mode??'train';settings.clean_min_laps=cleanMinLaps;
|
| 1241 |
if(report.population!==settings.population||report.generations_requested!==settings.generations||report.requested_ticks!==settings.ticks||(history&&history.length!==report.generations_completed))return null;
|
|
|
|
| 1388 |
}
|
| 1389 |
parsed.track.file=await validateBundleTrack(parsed.track);
|
| 1390 |
}
|
| 1391 |
+
if(parsed.recipe)parsed.recipe.settings=bundleSettings(parsed.recipe.settings);
|
| 1392 |
if(parsed.receipt){
|
| 1393 |
if(parsed.analysis){
|
| 1394 |
const clean=cleanRunReceipt(parsed.receipt);if(!clean)throw Error('Run receipt failed its allowlist or value checks');
|
help.html
CHANGED
|
@@ -18,7 +18,7 @@
|
|
| 18 |
<p class="small">This guide opens in a new tab to keep your current run and unsaved choices in place. Close this tab to return to the lab.</p>
|
| 19 |
<p class="callout">You can try the built-in replica tracks and browser network editor without installing the original game. This lab does not reproduce the full game, award official stars, or change game progress.</p>
|
| 20 |
<nav aria-label="Help topics"><ul>
|
| 21 |
-
<li><a href="#first-run">Start a run</a></li><li><a href="#concepts">Basic ideas</a></li><li><a href="#continue">Continue a winner</a></li><li><a href="#compare">Compare policies</a></li><li><a href="#storage">Files and storage</a></li><li><a href="#limits">Limits and compute</a></li><li><a href="#feedback">Feedback</a></li>
|
| 22 |
</ul></nav>
|
| 23 |
</header>
|
| 24 |
|
|
@@ -48,6 +48,11 @@
|
|
| 48 |
<p>Challenge checks use the selected driving settings, including collision elimination, and the chosen run duration or the track’s longer challenge deadline, capped at 300 simulated seconds. This extra replay may add processing time. A condition that is not met within that replay is not proof that the network could never meet it in a longer run.</p>
|
| 49 |
</section>
|
| 50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
<section class="section" id="continue">
|
| 52 |
<h2>Continue a winner</h2>
|
| 53 |
<p>After the result has been received, select a role from <strong>Winner to continue or evaluate</strong>:</p>
|
|
|
|
| 18 |
<p class="small">This guide opens in a new tab to keep your current run and unsaved choices in place. Close this tab to return to the lab.</p>
|
| 19 |
<p class="callout">You can try the built-in replica tracks and browser network editor without installing the original game. This lab does not reproduce the full game, award official stars, or change game progress.</p>
|
| 20 |
<nav aria-label="Help topics"><ul>
|
| 21 |
+
<li><a href="#first-run">Start a run</a></li><li><a href="#concepts">Basic ideas</a></li><li><a href="#freeze">Selective freezing</a></li><li><a href="#continue">Continue a winner</a></li><li><a href="#compare">Compare policies</a></li><li><a href="#storage">Files and storage</a></li><li><a href="#limits">Limits and compute</a></li><li><a href="#feedback">Feedback</a></li>
|
| 22 |
</ul></nav>
|
| 23 |
</header>
|
| 24 |
|
|
|
|
| 48 |
<p>Challenge checks use the selected driving settings, including collision elimination, and the chosen run duration or the track’s longer challenge deadline, capped at 300 simulated seconds. This extra replay may add processing time. A condition that is not met within that replay is not proof that the network could never meet it in a longer run.</p>
|
| 49 |
</section>
|
| 50 |
|
| 51 |
+
<section class="section" id="freeze">
|
| 52 |
+
<h2>Selective freezing</h2>
|
| 53 |
+
<p>In Training settings, open <strong>Selective freezing</strong> to keep selected parameters at their values in the starting network. Freezing an input holds its outgoing weights; freezing a hidden layer holds its incoming weights and biases; freezing an output holds its incoming weights and bias. The available choices and names come from the selected network. Freeze selections are part of saved recipes and can be edited later. Frozen evaluation runs the selected policy unchanged.</p>
|
| 54 |
+
</section>
|
| 55 |
+
|
| 56 |
<section class="section" id="continue">
|
| 57 |
<h2>Continue a winner</h2>
|
| 58 |
<p>After the result has been received, select a role from <strong>Winner to continue or evaluate</strong>:</p>
|
index.html
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>AI Learns To Drive</title>
|
| 2 |
<style>
|
| 3 |
:root{color-scheme:dark;font:16px system-ui;background:#0c1420;color:#e5edf5}body{max-width:1400px;margin:auto;padding:22px}h1{font-size:32px;margin:0}h2{font-size:21px;margin:0 0 14px}small,.hint{color:#a2b4c8;line-height:1.6}.grid{display:grid;grid-template-columns:minmax(360px,.9fr) minmax(0,1.25fr);gap:24px}.card{background:#152233;border:1px solid #2a3d52;border-radius:16px;padding:22px;margin-top:20px}label{display:block;margin:12px 0 5px}input,select,button{font:inherit;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:7px;padding:9px}input[type=number],select{width:100%;box-sizing:border-box}input[type=file]{max-width:100%;box-sizing:border-box}button{cursor:pointer}button.primary{background:#62dfb1;color:#102522;font-weight:700}button:disabled{opacity:.4;cursor:default}.row{display:grid;grid-template-columns:1fr 1fr;gap:15px}.reward{display:grid;grid-template-columns:1.7fr 1fr 70px 30px;gap:5px;margin:8px 0}.reward input{width:70px;box-sizing:border-box}a{color:#7ce4c3}canvas{width:100%;background:#09111b;border-radius:10px}#status{white-space:pre-wrap;line-height:1.7}table{width:100%;text-align:left;border-collapse:collapse;font-size:14px}td,th{padding:9px;border-bottom:1px solid #2a3d52}.pill{display:inline-block;background:#284539;border-radius:20px;padding:5px 12px;color:#91efc6;margin:6px 0}#error{color:#ffb5a2;white-space:pre-wrap}.toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding-bottom:16px;border-bottom:1px solid #2a3d52;margin-bottom:15px}.run-card{position:sticky;top:20px}details{margin-top:18px;border-top:1px solid #2a3d52;padding-top:14px}summary{cursor:pointer;font-weight:600;color:#c6d9e9}details[open]>summary{margin-bottom:12px}[hidden]{display:none!important}#map_note{font-size:14px}#runs{max-height:380px;overflow:auto}.table-scroll{overflow:auto}@media(max-width:850px){.grid{grid-template-columns:minmax(0,1fr)}.card{min-width:0}.run-card{position:static}body{padding:16px}}
|
| 4 |
-
.tabs{display:flex;flex-wrap:wrap;gap:10px;margin:20px 0}.tabs button[aria-selected=true]{background:#62dfb1;color:#102522}.library{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}.library input[type=text]{width:100%;box-sizing:border-box}.queue-row{display:flex;gap:8px;margin:8px 0}.queue-row select{flex:1}.pane{min-width:0}.map{min-height:300px;background:#09111b;border-radius:12px;padding:10px}.map canvas{display:block;width:100%;height:auto;max-height:320px;object-fit:contain}.map-legend{display:flex;gap:18px;flex-wrap:wrap;margin:10px 0;color:#c6d9e9;font-size:14px}pre{white-space:pre-wrap;overflow-wrap:anywhere}input[type=text]{width:100%;box-sizing:border-box}#libraries .row label>input,#libraries .row label>select{display:block;margin-top:6px}#editor_parameters input{max-width:240px} .eyebrow{color:#62dfb1;font-size:12px;letter-spacing:.18em;font-weight:800}.intro{font-size:19px;color:#b9cddd;max-width:820px;margin:10px 0 0}header{padding:12px 0 4px}header h1{font-size:clamp(30px,4vw,45px);letter-spacing:-.03em;margin-top:7px}.about{max-width:850px;font-size:14px;margin-top:15px}.about p{line-height:1.65}.card{box-shadow:0 10px 35px #050a1280}.tabs{position:sticky;top:0;z-index:3;background:#0c1420eF;padding:12px 0;border-bottom:1px solid #2a3d52}.tabs button{border-radius:12px;padding:11px 15px}.map-status{margin:7px 0;color:#dbe9f1;font-size:14px}#run{background:#62dfb1;color:#102522;font-weight:800;width:100%;margin-top:12px;padding:13px}.privacy-note{font-size:13px;line-height:1.5;color:#a2b4c8}.keep-result{display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid #3b566b;border-radius:10px;background:#102030;line-height:1.4}.keep-result input{margin:3px 0 0;flex:none} .terrain{display:inline-block;width:11px;height:11px;border-radius:3px;margin-right:4px;background:#607e96}.terrain.dirt{background:#b89561}.terrain.ice{background:#b9d9ed}.terrain.start{background:#66e5aa}.output-options{display:flex;flex-wrap:wrap;gap:5px 14px}.output-options label{display:flex;align-items:center;gap:5px;margin:5px 0}.output-options input{margin:0}#editor_outputs{margin:12px 0;padding:10px 12px;border:1px solid #49627c;border-radius:8px}#editor_outputs legend{padding:0 5px;color:#c6d9e9}@media(max-width:850px){.map{min-height:0}}dialog#appConfirm{box-sizing:border-box;width:min(92vw,440px);border:1px solid #54718d;border-radius:16px;padding:24px;background:#152233;color:#e5edf5;box-shadow:0 24px 80px #000b}dialog#appConfirm::backdrop{background:#02060bcc}#appConfirm h2{margin:0 0 10px}#appConfirm p{line-height:1.55;color:#c4d3e1;white-space:pre-wrap}#appConfirm .actions{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:22px}#appConfirm button{min-width:100px}#appConfirm button.danger{background:#8e3b37;color:#fff;border-color:#d7837e}</style>
|
| 5 |
<dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
|
| 6 |
<h2 id="appConfirmTitle">Confirm action</h2>
|
| 7 |
<p id="appConfirmMessage"></p>
|
|
@@ -79,6 +79,7 @@
|
|
| 79 |
<label for="crossover">Crossover</label><select id="crossover" disabled><option value="none">Off</option><option value="single_point">Single point</option><option value="uniform">Uniform</option></select>
|
| 80 |
<label for="decay">Weight decay</label><input id="decay" type="number" min="0" max="1" step="0.0001" value="0" disabled><small>Allowed 0–1; suggested 0–0.001. Decay 0.05 shrinks children by 5%.</small>
|
| 81 |
</details>
|
|
|
|
| 82 |
<details id="reward_settings"><summary>Rewards · presets and up to five metrics</summary>
|
| 83 |
<label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance" selected>First laps · distance only (+100 total score)</option><option value="center">Example mix · center, clearance, collisions</option><option value="clean">Clean driving · distance + collision penalty</option><option value="lap">Lap refinement · best lap only</option></select>
|
| 84 |
<div id="rewards"></div><button id="add" disabled>+ Add reward</button><small>Weights −100…+100; absolute shares normalize to 100%. Five distinct metrics maximum. The current vehicle runner accepts these metrics; choose them for the behavior you want to train.</small>
|
|
@@ -98,7 +99,7 @@
|
|
| 98 |
const defaults={population:4,generations:1,ticks:60,mutation:0.01,seed:42,
|
| 99 |
mutation_end:0.01,schedule:'fixed',selection:'best',parents:1,elite:1,crossover:'none',
|
| 100 |
decay:0,adaptive_mutation:false,control_hz:30,workers:1,collision:false,idle:false,
|
| 101 |
-
rewards:[{metric:'total_score',type:'default',weight:100}]};
|
| 102 |
const metrics=['total_score','total_speed','total_abs_steering','total_actual_distance',
|
| 103 |
'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
|
| 104 |
'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
|
|
@@ -114,6 +115,8 @@
|
|
| 114 |
}
|
| 115 |
for(const [key,choices] of [['schedule',['fixed','linear','geometric']],['selection',['best','tournament','roulette']],['crossover',['none','single_point','uniform']],['control_hz',[60,30,15]]])if(!choices.includes(clean[key]))throw Error('Invalid '+key);
|
| 116 |
for(const key of ['adaptive_mutation','collision','idle'])if(typeof clean[key]!=='boolean')throw Error('Invalid '+key);
|
|
|
|
|
|
|
| 117 |
if(clean.parents>clean.population||clean.elite>clean.population)throw Error('Parents/elites exceed population');
|
| 118 |
if(clean.mutation<=0||(clean.schedule!=='fixed'&&clean.mutation_end<=0))throw Error('This training runner requires positive mutation rates, including when continuing an uploaded network');
|
| 119 |
if(!Array.isArray(clean.rewards)||!clean.rewards.length||clean.rewards.length>5)throw Error('Use one to five rewards');
|
|
@@ -282,6 +285,32 @@
|
|
| 282 |
const fields=['population','generations','mutation','seed','mutation_end','schedule','selection','parents','elite','crossover','decay','adaptive_mutation','control_hz','workers','collision','idle'];
|
| 283 |
const booleans=['adaptive_mutation','collision','idle'];
|
| 284 |
const strings=['schedule','selection','crossover'];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 285 |
function rewards(){return [...q('rewards').children].map(row=>({metric:row.children[0].value,type:row.children[1].value,weight:Number(row.children[2].value)}));}
|
| 286 |
function rewardRow(r){
|
| 287 |
const row=document.createElement('div');row.className='reward';
|
|
@@ -297,13 +326,14 @@
|
|
| 297 |
}
|
| 298 |
function currentSettings(){
|
| 299 |
const data={};for(const name of fields)data[name]=booleans.includes(name)?q(name).checked:strings.includes(name)?q(name).value:Number(q(name).value);
|
| 300 |
-
data.ticks=Number(q('training_ticks').value);data.rewards=rewards();return api.settings(data);
|
| 301 |
}
|
| 302 |
function executableSettings(){const data=currentSettings();if(data.population*data.generations*data.ticks>4000000)throw Error('Run exceeds 4,000,000 vehicle-ticks');return data;}
|
| 303 |
function applySettings(value){
|
| 304 |
const data=api.settings(value);
|
| 305 |
for(const name of fields){if(booleans.includes(name))q(name).checked=data[name];else q(name).value=data[name];}
|
| 306 |
q('training_ticks').value=data.ticks;q('rewards').replaceChildren();data.rewards.forEach(rewardRow);
|
|
|
|
| 307 |
q('recipe_draft').value=JSON.stringify(data,null,2);
|
| 308 |
}
|
| 309 |
const editable=[...fields,'training_ticks','add','reward_preset','preset','starter_settings_reset'];
|
|
@@ -311,7 +341,7 @@
|
|
| 311 |
q('end_rate_group').hidden=false;
|
| 312 |
const firstRunSettings={...api.defaults,population:32,generations:20,ticks:900,mutation:0.3,mutation_end:0.3,parents:1,elite:1,decay:0,workers:1,collision:false,idle:false,rewards:[{metric:'total_score',type:'default',weight:100}]};
|
| 313 |
applySettings(firstRunSettings);q('preset').value='starter';q('reward_preset').value='distance';
|
| 314 |
-
window.getTrainingSettings=executableSettings;
|
| 315 |
let stagedPortableRecipe=false;
|
| 316 |
window.getPortableRecipe=()=>{
|
| 317 |
if(stagedPortableRecipe)return {slot:q('recipe_slot').value,name:q('recipe_name').value,settings:currentSettings()};
|
|
|
|
| 1 |
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>AI Learns To Drive</title>
|
| 2 |
<style>
|
| 3 |
:root{color-scheme:dark;font:16px system-ui;background:#0c1420;color:#e5edf5}body{max-width:1400px;margin:auto;padding:22px}h1{font-size:32px;margin:0}h2{font-size:21px;margin:0 0 14px}small,.hint{color:#a2b4c8;line-height:1.6}.grid{display:grid;grid-template-columns:minmax(360px,.9fr) minmax(0,1.25fr);gap:24px}.card{background:#152233;border:1px solid #2a3d52;border-radius:16px;padding:22px;margin-top:20px}label{display:block;margin:12px 0 5px}input,select,button{font:inherit;background:#0c1725;color:#e5edf5;border:1px solid #49627c;border-radius:7px;padding:9px}input[type=number],select{width:100%;box-sizing:border-box}input[type=file]{max-width:100%;box-sizing:border-box}button{cursor:pointer}button.primary{background:#62dfb1;color:#102522;font-weight:700}button:disabled{opacity:.4;cursor:default}.row{display:grid;grid-template-columns:1fr 1fr;gap:15px}.reward{display:grid;grid-template-columns:1.7fr 1fr 70px 30px;gap:5px;margin:8px 0}.reward input{width:70px;box-sizing:border-box}a{color:#7ce4c3}canvas{width:100%;background:#09111b;border-radius:10px}#status{white-space:pre-wrap;line-height:1.7}table{width:100%;text-align:left;border-collapse:collapse;font-size:14px}td,th{padding:9px;border-bottom:1px solid #2a3d52}.pill{display:inline-block;background:#284539;border-radius:20px;padding:5px 12px;color:#91efc6;margin:6px 0}#error{color:#ffb5a2;white-space:pre-wrap}.toolbar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;padding-bottom:16px;border-bottom:1px solid #2a3d52;margin-bottom:15px}.run-card{position:sticky;top:20px}details{margin-top:18px;border-top:1px solid #2a3d52;padding-top:14px}summary{cursor:pointer;font-weight:600;color:#c6d9e9}details[open]>summary{margin-bottom:12px}[hidden]{display:none!important}#map_note{font-size:14px}#runs{max-height:380px;overflow:auto}.table-scroll{overflow:auto}@media(max-width:850px){.grid{grid-template-columns:minmax(0,1fr)}.card{min-width:0}.run-card{position:static}body{padding:16px}}
|
| 4 |
+
.tabs{display:flex;flex-wrap:wrap;gap:10px;margin:20px 0}.tabs button[aria-selected=true]{background:#62dfb1;color:#102522}.library{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:20px}.library input[type=text]{width:100%;box-sizing:border-box}.queue-row{display:flex;gap:8px;margin:8px 0}.queue-row select{flex:1}.pane{min-width:0}.map{min-height:300px;background:#09111b;border-radius:12px;padding:10px}.map canvas{display:block;width:100%;height:auto;max-height:320px;object-fit:contain}.map-legend{display:flex;gap:18px;flex-wrap:wrap;margin:10px 0;color:#c6d9e9;font-size:14px}pre{white-space:pre-wrap;overflow-wrap:anywhere}input[type=text]{width:100%;box-sizing:border-box}#libraries .row label>input,#libraries .row label>select{display:block;margin-top:6px}#editor_parameters input{max-width:240px} .eyebrow{color:#62dfb1;font-size:12px;letter-spacing:.18em;font-weight:800}.intro{font-size:19px;color:#b9cddd;max-width:820px;margin:10px 0 0}header{padding:12px 0 4px}header h1{font-size:clamp(30px,4vw,45px);letter-spacing:-.03em;margin-top:7px}.about{max-width:850px;font-size:14px;margin-top:15px}.about p{line-height:1.65}.card{box-shadow:0 10px 35px #050a1280}.tabs{position:sticky;top:0;z-index:3;background:#0c1420eF;padding:12px 0;border-bottom:1px solid #2a3d52}.tabs button{border-radius:12px;padding:11px 15px}.map-status{margin:7px 0;color:#dbe9f1;font-size:14px}#run{background:#62dfb1;color:#102522;font-weight:800;width:100%;margin-top:12px;padding:13px}.privacy-note{font-size:13px;line-height:1.5;color:#a2b4c8}.keep-result{display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid #3b566b;border-radius:10px;background:#102030;line-height:1.4}.keep-result input{margin:3px 0 0;flex:none} .terrain{display:inline-block;width:11px;height:11px;border-radius:3px;margin-right:4px;background:#607e96}.terrain.dirt{background:#b89561}.terrain.ice{background:#b9d9ed}.terrain.start{background:#66e5aa}.output-options{display:flex;flex-wrap:wrap;gap:5px 14px}.output-options label{display:flex;align-items:center;gap:5px;margin:5px 0}.output-options input{margin:0}#editor_outputs{margin:12px 0;padding:10px 12px;border:1px solid #49627c;border-radius:8px}#editor_outputs legend{padding:0 5px;color:#c6d9e9}.freeze-group{min-width:190px;flex:1;margin:8px 0;padding:8px 12px;border:1px solid #49627c;border-radius:8px}.freeze-group summary{padding:0 5px;color:#c6d9e9;cursor:pointer}.freeze-group label{display:block;margin:6px 0}@media(max-width:850px){.map{min-height:0}}dialog#appConfirm{box-sizing:border-box;width:min(92vw,440px);border:1px solid #54718d;border-radius:16px;padding:24px;background:#152233;color:#e5edf5;box-shadow:0 24px 80px #000b}dialog#appConfirm::backdrop{background:#02060bcc}#appConfirm h2{margin:0 0 10px}#appConfirm p{line-height:1.55;color:#c4d3e1;white-space:pre-wrap}#appConfirm .actions{display:flex;justify-content:flex-end;gap:10px;flex-wrap:wrap;margin-top:22px}#appConfirm button{min-width:100px}#appConfirm button.danger{background:#8e3b37;color:#fff;border-color:#d7837e}</style>
|
| 5 |
<dialog id="appConfirm" aria-labelledby="appConfirmTitle" aria-describedby="appConfirmMessage">
|
| 6 |
<h2 id="appConfirmTitle">Confirm action</h2>
|
| 7 |
<p id="appConfirmMessage"></p>
|
|
|
|
| 79 |
<label for="crossover">Crossover</label><select id="crossover" disabled><option value="none">Off</option><option value="single_point">Single point</option><option value="uniform">Uniform</option></select>
|
| 80 |
<label for="decay">Weight decay</label><input id="decay" type="number" min="0" max="1" step="0.0001" value="0" disabled><small>Allowed 0–1; suggested 0–0.001. Decay 0.05 shrinks children by 5%.</small>
|
| 81 |
</details>
|
| 82 |
+
<details id="freeze_settings"><summary>Selective freezing · optional</summary><p class="hint">Keep selected sensor inputs, hidden layers, or output controls unchanged while training. Choices follow the selected network and are saved with recipes. Frozen evaluation always uses an empty freeze selection.</p><div id="freeze_status" class="hint" role="status">Select a network to choose components.</div><div id="freeze_controls" class="row"></div></details>
|
| 83 |
<details id="reward_settings"><summary>Rewards · presets and up to five metrics</summary>
|
| 84 |
<label for="reward_preset">Reward preset</label><select id="reward_preset" disabled><option value="custom">Custom</option><option value="distance" selected>First laps · distance only (+100 total score)</option><option value="center">Example mix · center, clearance, collisions</option><option value="clean">Clean driving · distance + collision penalty</option><option value="lap">Lap refinement · best lap only</option></select>
|
| 85 |
<div id="rewards"></div><button id="add" disabled>+ Add reward</button><small>Weights −100…+100; absolute shares normalize to 100%. Five distinct metrics maximum. The current vehicle runner accepts these metrics; choose them for the behavior you want to train.</small>
|
|
|
|
| 99 |
const defaults={population:4,generations:1,ticks:60,mutation:0.01,seed:42,
|
| 100 |
mutation_end:0.01,schedule:'fixed',selection:'best',parents:1,elite:1,crossover:'none',
|
| 101 |
decay:0,adaptive_mutation:false,control_hz:30,workers:1,collision:false,idle:false,
|
| 102 |
+
rewards:[{metric:'total_score',type:'default',weight:100}],freeze:{layers:[],inputs:[],outputs:[]}};
|
| 103 |
const metrics=['total_score','total_speed','total_abs_steering','total_actual_distance',
|
| 104 |
'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
|
| 105 |
'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
|
|
|
|
| 115 |
}
|
| 116 |
for(const [key,choices] of [['schedule',['fixed','linear','geometric']],['selection',['best','tournament','roulette']],['crossover',['none','single_point','uniform']],['control_hz',[60,30,15]]])if(!choices.includes(clean[key]))throw Error('Invalid '+key);
|
| 117 |
for(const key of ['adaptive_mutation','collision','idle'])if(typeof clean[key]!=='boolean')throw Error('Invalid '+key);
|
| 118 |
+
if(!clean.freeze||typeof clean.freeze!=='object'||Array.isArray(clean.freeze)||Object.keys(clean.freeze).sort().join()!=='inputs,layers,outputs')throw Error('Invalid freeze settings');
|
| 119 |
+
for(const [key,max] of [['layers',10],['inputs',19],['outputs',4]]){const values=clean.freeze[key];if(!Array.isArray(values)||values.some(v=>!Number.isInteger(v)||v<(key==='layers'?1:0)||v>max)||new Set(values).size!==values.length)throw Error('Invalid frozen '+key);clean.freeze[key]=[...values].sort((a,b)=>a-b);}
|
| 120 |
if(clean.parents>clean.population||clean.elite>clean.population)throw Error('Parents/elites exceed population');
|
| 121 |
if(clean.mutation<=0||(clean.schedule!=='fixed'&&clean.mutation_end<=0))throw Error('This training runner requires positive mutation rates, including when continuing an uploaded network');
|
| 122 |
if(!Array.isArray(clean.rewards)||!clean.rewards.length||clean.rewards.length>5)throw Error('Use one to five rewards');
|
|
|
|
| 285 |
const fields=['population','generations','mutation','seed','mutation_end','schedule','selection','parents','elite','crossover','decay','adaptive_mutation','control_hz','workers','collision','idle'];
|
| 286 |
const booleans=['adaptive_mutation','collision','idle'];
|
| 287 |
const strings=['schedule','selection','crossover'];
|
| 288 |
+
let freezeNetwork=null;
|
| 289 |
+
const freezeLabels={outputs:['Steering','Acceleration','Handbrake','Brake','Boost']};
|
| 290 |
+
function freezeValue(){const f=api.settings({...api.defaults,freeze:{layers:[],inputs:[],outputs:[]}}).freeze;return f;}
|
| 291 |
+
function includeUnavailableFreezeSelections(kind,items,selectedIds){
|
| 292 |
+
const available=new Set(items.map(item=>item.id)),noun=kind==='layers'?'hidden layer':kind==='inputs'?'sensor input':'output';
|
| 293 |
+
const unavailable=selectedIds.filter(id=>!available.has(id)).map(id=>({id,unavailable:true,label:'Unavailable '+noun+' index '+id}));
|
| 294 |
+
return [...items,...unavailable];
|
| 295 |
+
}
|
| 296 |
+
function renderFreeze(){
|
| 297 |
+
const box=q('freeze_controls'),status=q('freeze_status'),openGroups=new Map([...box.querySelectorAll('details.freeze-group')].map(group=>[group.dataset.freezeGroup,group.open]));box.replaceChildren();
|
| 298 |
+
if(!freezeNetwork){status.textContent='Select a network to choose components.';return;}
|
| 299 |
+
const {shape,sensors,outputs}=freezeNetwork;
|
| 300 |
+
const groups=[['layers',Array.from({length:Math.max(0,shape.length-2)},(_,i)=>({id:i+1,label:'Hidden layer '+(i+1)+' · '+shape[i+1]+' nodes'}))],
|
| 301 |
+
['inputs',sensors.map((sensor,i)=>({id:i,label:'Input '+i+' · '+(sensor.$type==='raycast'?'Raycast '+sensor.Degrees+'°':sensor.$type.replaceAll('_',' '))}))],
|
| 302 |
+
['outputs',outputs.map((output,i)=>({id:i,label:'Output '+i+' · '+(freezeLabels.outputs[output]||('Control '+output))}))]];
|
| 303 |
+
for(const [kind,availableItems] of groups){const items=includeUnavailableFreezeSelections(kind,availableItems,selectedFreeze[kind]);const field=document.createElement('details');field.className='freeze-group';field.dataset.freezeGroup=kind;field.open=openGroups.get(kind)??false;const summary=document.createElement('summary');summary.textContent=(kind==='layers'?'Hidden layers':kind==='inputs'?'Sensor inputs':'Outputs')+' ('+items.length+')';field.append(summary);
|
| 304 |
+
for(const item of items){const label=document.createElement('label'),input=document.createElement('input');input.type='checkbox';input.dataset.freezeKind=kind;input.value=String(item.id);input.checked=selectedFreeze[kind].includes(item.id);label.append(input,document.createTextNode(' '+item.label));field.append(label);}
|
| 305 |
+
box.append(field);
|
| 306 |
+
}
|
| 307 |
+
const invalid=['layers','inputs','outputs'].flatMap(kind=>selectedFreeze[kind].filter(id=>!itemsFor(kind).includes(id)).map(id=>kind+' '+id));
|
| 308 |
+
status.textContent=invalid.length?'Some saved selections are unavailable. Uncheck their visible “Unavailable” entries before starting training.':'Selected network: '+shape.join(' → ')+' · '+sensors.length+' inputs · '+outputs.length+' outputs.';
|
| 309 |
+
}
|
| 310 |
+
const selectedFreeze=freezeValue();
|
| 311 |
+
function itemsFor(kind){if(!freezeNetwork)return[];if(kind==='layers')return Array.from({length:freezeNetwork.shape.length-2},(_,i)=>i+1);if(kind==='inputs')return freezeNetwork.sensors.map((_,i)=>i);return freezeNetwork.outputs.map((_,i)=>i);}
|
| 312 |
+
window.setFreezeNetwork=network=>{freezeNetwork=network?{shape:[...network.NeuralNetwork.Shape],sensors:network.Sensors.map(x=>({...x})),outputs:[...network.Outputs]}:null;renderFreeze();};
|
| 313 |
+
q('freeze_controls').addEventListener('change',event=>{const input=event.target;if(!input.matches('input[data-freeze-kind]'))return;const kind=input.dataset.freezeKind,id=Number(input.value);selectedFreeze[kind]=input.checked?[...selectedFreeze[kind],id].sort((a,b)=>a-b):selectedFreeze[kind].filter(x=>x!==id);q('preset').value='custom';renderFreeze();});
|
| 314 |
function rewards(){return [...q('rewards').children].map(row=>({metric:row.children[0].value,type:row.children[1].value,weight:Number(row.children[2].value)}));}
|
| 315 |
function rewardRow(r){
|
| 316 |
const row=document.createElement('div');row.className='reward';
|
|
|
|
| 326 |
}
|
| 327 |
function currentSettings(){
|
| 328 |
const data={};for(const name of fields)data[name]=booleans.includes(name)?q(name).checked:strings.includes(name)?q(name).value:Number(q(name).value);
|
| 329 |
+
data.ticks=Number(q('training_ticks').value);data.rewards=rewards();data.freeze={layers:[...selectedFreeze.layers],inputs:[...selectedFreeze.inputs],outputs:[...selectedFreeze.outputs]};return api.settings(data);
|
| 330 |
}
|
| 331 |
function executableSettings(){const data=currentSettings();if(data.population*data.generations*data.ticks>4000000)throw Error('Run exceeds 4,000,000 vehicle-ticks');return data;}
|
| 332 |
function applySettings(value){
|
| 333 |
const data=api.settings(value);
|
| 334 |
for(const name of fields){if(booleans.includes(name))q(name).checked=data[name];else q(name).value=data[name];}
|
| 335 |
q('training_ticks').value=data.ticks;q('rewards').replaceChildren();data.rewards.forEach(rewardRow);
|
| 336 |
+
for(const kind of ['layers','inputs','outputs'])selectedFreeze[kind]=[...data.freeze[kind]];renderFreeze();
|
| 337 |
q('recipe_draft').value=JSON.stringify(data,null,2);
|
| 338 |
}
|
| 339 |
const editable=[...fields,'training_ticks','add','reward_preset','preset','starter_settings_reset'];
|
|
|
|
| 341 |
q('end_rate_group').hidden=false;
|
| 342 |
const firstRunSettings={...api.defaults,population:32,generations:20,ticks:900,mutation:0.3,mutation_end:0.3,parents:1,elite:1,decay:0,workers:1,collision:false,idle:false,rewards:[{metric:'total_score',type:'default',weight:100}]};
|
| 343 |
applySettings(firstRunSettings);q('preset').value='starter';q('reward_preset').value='distance';
|
| 344 |
+
window.getTrainingSettings=()=>{const data=executableSettings();if(q('run_mode')?.value==='evaluate')data.freeze={layers:[],inputs:[],outputs:[]};else if(freezeNetwork){for(const kind of ['layers','inputs','outputs'])if(data.freeze[kind].some(id=>!itemsFor(kind).includes(id)))throw Error('Remove frozen selections that do not exist on the selected network');}else if(data.freeze.layers.length||data.freeze.inputs.length||data.freeze.outputs.length)throw Error('Select a network before using selective freezing');return data;};
|
| 345 |
let stagedPortableRecipe=false;
|
| 346 |
window.getPortableRecipe=()=>{
|
| 347 |
if(stagedPortableRecipe)return {slot:q('recipe_slot').value,name:q('recipe_name').value,settings:currentSettings()};
|
native/selective-freeze-build-receipt.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema": "ald-native-cross-build-attempt-v1",
|
| 3 |
+
"started_utc": "2026-10-14T16:58:09.004157+00:00",
|
| 4 |
+
"command": [
|
| 5 |
+
"/Users/tiga/.cargo/bin/cargo",
|
| 6 |
+
"+1.95.0",
|
| 7 |
+
"build",
|
| 8 |
+
"--target",
|
| 9 |
+
"x86_64-unknown-linux-gnu",
|
| 10 |
+
"--manifest-path",
|
| 11 |
+
"build/source/Cargo.toml",
|
| 12 |
+
"--release",
|
| 13 |
+
"--locked",
|
| 14 |
+
"--offline",
|
| 15 |
+
"--no-default-features",
|
| 16 |
+
"--features",
|
| 17 |
+
"cli",
|
| 18 |
+
"--bin",
|
| 19 |
+
"altd-sim"
|
| 20 |
+
],
|
| 21 |
+
"environment": {
|
| 22 |
+
"CARGO_TARGET_DIR": "/Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-target",
|
| 23 |
+
"CARGO_PROFILE_RELEASE_LTO": "false",
|
| 24 |
+
"CARGO_PROFILE_RELEASE_CODEGEN_UNITS": "16",
|
| 25 |
+
"CARGO_PROFILE_RELEASE_DEBUG": "0",
|
| 26 |
+
"CARGO_BUILD_JOBS": "4",
|
| 27 |
+
"CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER": "/Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-tools/linux-linker",
|
| 28 |
+
"RUSTFLAGS": "--sysroot /Volumes/PATRIOT/ALD-TAO-lab/hf-winners-evaluation-v1.2-20261013/build/cross-sysroot -C target-cpu=x86-64"
|
| 29 |
+
},
|
| 30 |
+
"status": "compiled",
|
| 31 |
+
"exit_code": 0,
|
| 32 |
+
"artifact": {
|
| 33 |
+
"path": "build/artifacts/altd-sim",
|
| 34 |
+
"bytes": 3647808,
|
| 35 |
+
"sha256": "ce31f754f6b6f3afaf4dcc44c1e6fda3e6414eb2924fa167b8778523bcaf2070"
|
| 36 |
+
},
|
| 37 |
+
"elapsed_seconds": 25.666
|
| 38 |
+
}
|
native/selective-freeze-source.tar.gz
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:297d2ce34569994acd2a477e64c5315cb2081699b4333b8abdabb3ff7451d8db
|
| 3 |
+
size 491438
|
portable_bundle.py
CHANGED
|
@@ -35,9 +35,9 @@ RECIPE_KEYS = {
|
|
| 35 |
"population", "generations", "ticks", "mutation", "seed", "mutation_end",
|
| 36 |
"schedule", "selection", "parents", "elite", "crossover", "decay",
|
| 37 |
"adaptive_mutation", "control_hz", "workers", "collision", "idle", "rewards",
|
| 38 |
-
"mode", "clean_min_laps",
|
| 39 |
}
|
| 40 |
-
LEGACY_RECIPE_KEYS = RECIPE_KEYS - {"mode", "clean_min_laps"}
|
| 41 |
METRICS = {
|
| 42 |
"total_score", "total_speed", "total_abs_steering", "total_actual_distance",
|
| 43 |
"total_drifting_amount", "total_momentum_change_frequency", "total_throttle_change_frequency",
|
|
@@ -274,7 +274,8 @@ def load_analysis_archive(raw: bytes) -> tuple[dict[str, Any], dict[str, bytes]]
|
|
| 274 |
and not (kind == "average" and metric not in AVERAGE_METRICS)]):
|
| 275 |
raise BundleError("analysis metric or reward channel definitions are invalid")
|
| 276 |
settings = analysis.get("settings")
|
| 277 |
-
if not isinstance(settings, dict)
|
|
|
|
| 278 |
raise BundleError("analysis validated settings are missing")
|
| 279 |
validate_settings(settings)
|
| 280 |
if (settings.get("mode") != mode or settings.get("ticks") != conditions["requested_ticks"]
|
|
@@ -501,10 +502,26 @@ def _is_number(value: Any, low: float, high: float) -> bool:
|
|
| 501 |
return type(value) in (int, float) and math.isfinite(value) and low <= value <= high
|
| 502 |
|
| 503 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
def validate_settings(value: Any) -> dict[str, Any]:
|
| 505 |
settings = _strict_keys(value, RECIPE_KEYS, LEGACY_RECIPE_KEYS, "recipe settings")
|
| 506 |
settings.setdefault("mode", "train")
|
| 507 |
settings.setdefault("clean_min_laps", 2)
|
|
|
|
|
|
|
| 508 |
bounds = {
|
| 509 |
"population": (1, 128), "generations": (1, 1000), "ticks": (1, 18000),
|
| 510 |
"seed": (0, 2147483647), "parents": (1, 128), "elite": (0, 128), "workers": (1, 4),
|
|
|
|
| 35 |
"population", "generations", "ticks", "mutation", "seed", "mutation_end",
|
| 36 |
"schedule", "selection", "parents", "elite", "crossover", "decay",
|
| 37 |
"adaptive_mutation", "control_hz", "workers", "collision", "idle", "rewards",
|
| 38 |
+
"mode", "clean_min_laps", "freeze",
|
| 39 |
}
|
| 40 |
+
LEGACY_RECIPE_KEYS = RECIPE_KEYS - {"mode", "clean_min_laps", "freeze"}
|
| 41 |
METRICS = {
|
| 42 |
"total_score", "total_speed", "total_abs_steering", "total_actual_distance",
|
| 43 |
"total_drifting_amount", "total_momentum_change_frequency", "total_throttle_change_frequency",
|
|
|
|
| 274 |
and not (kind == "average" and metric not in AVERAGE_METRICS)]):
|
| 275 |
raise BundleError("analysis metric or reward channel definitions are invalid")
|
| 276 |
settings = analysis.get("settings")
|
| 277 |
+
if (not isinstance(settings, dict)
|
| 278 |
+
or set(settings) not in (RECIPE_KEYS, RECIPE_KEYS - {"freeze"})):
|
| 279 |
raise BundleError("analysis validated settings are missing")
|
| 280 |
validate_settings(settings)
|
| 281 |
if (settings.get("mode") != mode or settings.get("ticks") != conditions["requested_ticks"]
|
|
|
|
| 502 |
return type(value) in (int, float) and math.isfinite(value) and low <= value <= high
|
| 503 |
|
| 504 |
|
| 505 |
+
def validate_freeze(value: Any) -> dict[str, list[int]]:
|
| 506 |
+
"""Validate the fixed-index network freeze mask used by hosted recipes and reports."""
|
| 507 |
+
if not isinstance(value, dict) or set(value) != {"layers", "inputs", "outputs"}:
|
| 508 |
+
raise BundleError("recipe freeze mask has unsupported fields")
|
| 509 |
+
bounds = {"layers": (1, 10), "inputs": (0, 19), "outputs": (0, 4)}
|
| 510 |
+
for key, (low, high) in bounds.items():
|
| 511 |
+
indices = value[key]
|
| 512 |
+
if (not isinstance(indices, list)
|
| 513 |
+
or any(type(index) is not int or not low <= index <= high for index in indices)
|
| 514 |
+
or indices != sorted(set(indices))):
|
| 515 |
+
raise BundleError("recipe freeze mask indices are invalid")
|
| 516 |
+
return value
|
| 517 |
+
|
| 518 |
+
|
| 519 |
def validate_settings(value: Any) -> dict[str, Any]:
|
| 520 |
settings = _strict_keys(value, RECIPE_KEYS, LEGACY_RECIPE_KEYS, "recipe settings")
|
| 521 |
settings.setdefault("mode", "train")
|
| 522 |
settings.setdefault("clean_min_laps", 2)
|
| 523 |
+
if "freeze" in settings:
|
| 524 |
+
validate_freeze(settings["freeze"])
|
| 525 |
bounds = {
|
| 526 |
"population": (1, 128), "generations": (1, 1000), "ticks": (1, 18000),
|
| 527 |
"seed": (0, 2147483647), "parents": (1, 128), "elite": (0, 128), "workers": (1, 4),
|
training_config.py
CHANGED
|
@@ -5,12 +5,27 @@ import math
|
|
| 5 |
DEFAULTS={'mode':'train','clean_min_laps':2,'population':4,'generations':1,'ticks':60,'mutation':.01,'seed':42,
|
| 6 |
'mutation_end':.01,'schedule':'fixed','selection':'best','parents':1,'elite':1,
|
| 7 |
'crossover':'none','decay':0,'adaptive_mutation':False,'control_hz':30,'workers':1,
|
| 8 |
-
'collision':False,'idle':False,'
|
|
|
|
| 9 |
METRICS={'total_score','total_speed','total_abs_steering','total_actual_distance',
|
| 10 |
'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
|
| 11 |
'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
|
| 12 |
'network_novelty','collision_count','best_lap_performance','total_racing_line_efficiency'}
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
def validate_config(value=None):
|
| 15 |
if value is None:return copy.deepcopy(DEFAULTS)
|
| 16 |
if not isinstance(value,dict) or set(value)-set(DEFAULTS):raise ValueError('Unexpected training settings')
|
|
@@ -26,6 +41,7 @@ def validate_config(value=None):
|
|
| 26 |
if c[key] not in choices or (key=='control_hz' and type(c[key]) is not int):raise ValueError('Invalid '+key)
|
| 27 |
for key in ('adaptive_mutation','collision','idle'):
|
| 28 |
if type(c[key]) is not bool:raise ValueError('Invalid '+key)
|
|
|
|
| 29 |
if c['mode']=='train' and (c['parents']>c['population'] or c['elite']>c['population']):raise ValueError('Parents/elites exceed population')
|
| 30 |
if c['mode']=='train' and (c['mutation']<=0 or (c['schedule']!='fixed' and c['mutation_end']<=0)):raise ValueError('This training runner requires positive mutation rates, including when continuing an uploaded network')
|
| 31 |
# Echo the rate actually passed to the native CLI, not an unused form value.
|
|
@@ -40,6 +56,6 @@ def validate_config(value=None):
|
|
| 40 |
if not any(r['weight'] for r in clean):raise ValueError('A reward weight must be nonzero')
|
| 41 |
c['rewards']=clean
|
| 42 |
if c['mode']=='evaluate':
|
| 43 |
-
c.update(population=1,generations=1,mutation=0,mutation_end=0,decay=0,adaptive_mutation=False,parents=1,elite=0,crossover='none',selection='best',schedule='fixed')
|
| 44 |
if c['population']*c['generations']*c['ticks']>4_000_000:raise ValueError('Run exceeds preview work limit (4,000,000 vehicle-ticks)')
|
| 45 |
return c
|
|
|
|
| 5 |
DEFAULTS={'mode':'train','clean_min_laps':2,'population':4,'generations':1,'ticks':60,'mutation':.01,'seed':42,
|
| 6 |
'mutation_end':.01,'schedule':'fixed','selection':'best','parents':1,'elite':1,
|
| 7 |
'crossover':'none','decay':0,'adaptive_mutation':False,'control_hz':30,'workers':1,
|
| 8 |
+
'collision':False,'idle':False,'freeze':{'layers':[],'inputs':[],'outputs':[]},
|
| 9 |
+
'rewards':[{'metric':'total_score','type':'default','weight':100}]}
|
| 10 |
METRICS={'total_score','total_speed','total_abs_steering','total_actual_distance',
|
| 11 |
'total_drifting_amount','total_momentum_change_frequency','total_throttle_change_frequency',
|
| 12 |
'total_braking_frequency','total_distance_from_wall','total_distance_from_center',
|
| 13 |
'network_novelty','collision_count','best_lap_performance','total_racing_line_efficiency'}
|
| 14 |
|
| 15 |
+
def validate_freeze(value):
|
| 16 |
+
"""Check the settings envelope; the uploaded network supplies exact bounds."""
|
| 17 |
+
if not isinstance(value,dict) or set(value)!={'layers','inputs','outputs'}:
|
| 18 |
+
raise ValueError('Invalid freeze selection')
|
| 19 |
+
result={}
|
| 20 |
+
for key,low,high in (('layers',1,10),('inputs',0,19),('outputs',0,4)):
|
| 21 |
+
items=value[key]
|
| 22 |
+
if (not isinstance(items,list) or len(items)>high-low+1 or
|
| 23 |
+
any(type(item) is not int or not low<=item<=high for item in items) or
|
| 24 |
+
items!=sorted(set(items))):
|
| 25 |
+
raise ValueError('Invalid frozen '+key)
|
| 26 |
+
result[key]=items[:]
|
| 27 |
+
return result
|
| 28 |
+
|
| 29 |
def validate_config(value=None):
|
| 30 |
if value is None:return copy.deepcopy(DEFAULTS)
|
| 31 |
if not isinstance(value,dict) or set(value)-set(DEFAULTS):raise ValueError('Unexpected training settings')
|
|
|
|
| 41 |
if c[key] not in choices or (key=='control_hz' and type(c[key]) is not int):raise ValueError('Invalid '+key)
|
| 42 |
for key in ('adaptive_mutation','collision','idle'):
|
| 43 |
if type(c[key]) is not bool:raise ValueError('Invalid '+key)
|
| 44 |
+
c['freeze']=validate_freeze(c['freeze'])
|
| 45 |
if c['mode']=='train' and (c['parents']>c['population'] or c['elite']>c['population']):raise ValueError('Parents/elites exceed population')
|
| 46 |
if c['mode']=='train' and (c['mutation']<=0 or (c['schedule']!='fixed' and c['mutation_end']<=0)):raise ValueError('This training runner requires positive mutation rates, including when continuing an uploaded network')
|
| 47 |
# Echo the rate actually passed to the native CLI, not an unused form value.
|
|
|
|
| 56 |
if not any(r['weight'] for r in clean):raise ValueError('A reward weight must be nonzero')
|
| 57 |
c['rewards']=clean
|
| 58 |
if c['mode']=='evaluate':
|
| 59 |
+
c.update(population=1,generations=1,mutation=0,mutation_end=0,decay=0,adaptive_mutation=False,parents=1,elite=0,crossover='none',selection='best',schedule='fixed',freeze={'layers':[],'inputs':[],'outputs':[]})
|
| 60 |
if c['population']*c['generations']*c['ticks']>4_000_000:raise ValueError('Run exceeds preview work limit (4,000,000 vehicle-ticks)')
|
| 61 |
return c
|
worker.py
CHANGED
|
@@ -111,6 +111,43 @@ def network_input(data):
|
|
| 111 |
'NeuronsCount':sum(shape),'TotalParams':sum((a+1)*b for a,b in zip(shape,shape[1:])),
|
| 112 |
'Weights':weights,'Biases':biases}}
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
def track_input(data):
|
| 115 |
value=read_json(data)
|
| 116 |
challenges=value.get('Challenges',[])
|
|
@@ -169,6 +206,9 @@ def check_current_network(work, command, env, track, template, config, result, t
|
|
| 169 |
if not needs_observations(track,track_sha):
|
| 170 |
return resolve_check(track,template,config,[],**kwargs)
|
| 171 |
check_command=list(command)
|
|
|
|
|
|
|
|
|
|
| 172 |
def option(name,value):
|
| 173 |
check_command[check_command.index(name)+1]=str(value)
|
| 174 |
n=template['NeuralNetwork']
|
|
@@ -210,6 +250,7 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
|
|
| 210 |
started=time.perf_counter()
|
| 211 |
config=validate_config(config)
|
| 212 |
track=track_input(track_bytes); template=network_input(network_bytes)
|
|
|
|
| 213 |
# Deployment paths are supplied by trusted application configuration, never uploads.
|
| 214 |
binary=Path(binary or ROOT/'target/release/altd-sim').resolve()
|
| 215 |
importer=Path(importer or ROOT/'target/release/examples/extract_saved_track').resolve()
|
|
@@ -248,6 +289,8 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
|
|
| 248 |
'--checkpoint-every','0','--analysis','--clean-min-laps',str(config['clean_min_laps']),
|
| 249 |
'--eliminate-on-wall' if config['collision'] else '--no-eliminate-on-wall',
|
| 250 |
'--idle-eliminate' if config['idle'] else '--no-idle-eliminate']
|
|
|
|
|
|
|
| 251 |
if config['mode']=='evaluate':command.append('--evaluate-frozen')
|
| 252 |
if gpu_library is not None: command.append('--gpu')
|
| 253 |
subprocess.run(command,cwd=work,env=env,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=25,check=True)
|
|
@@ -255,6 +298,7 @@ def run_native(track_bytes,network_bytes,*,binary=None,importer=None,scene_templ
|
|
| 255 |
candidate=out/'candidate.json'
|
| 256 |
if candidate.stat().st_size>1024*1024: raise ValueError('Output too large')
|
| 257 |
trained=json.loads(candidate.read_text())
|
|
|
|
| 258 |
n['Weights']=trained['weights']; n['Biases']=trained['biases']
|
| 259 |
result=(network_bytes if config['mode']=='evaluate' else gzip.compress(json.dumps(template,allow_nan=False).encode(),mtime=0))
|
| 260 |
network_input(result)
|
|
|
|
| 111 |
'NeuronsCount':sum(shape),'TotalParams':sum((a+1)*b for a,b in zip(shape,shape[1:])),
|
| 112 |
'Weights':weights,'Biases':biases}}
|
| 113 |
|
| 114 |
+
def check_freeze_shape(freeze,shape):
|
| 115 |
+
"""Resolve selection against this policy, with at least one trainable parameter."""
|
| 116 |
+
if any(layer>=len(shape)-1 for layer in freeze['layers']):
|
| 117 |
+
raise ValueError('Frozen hidden layer exceeds network shape')
|
| 118 |
+
if any(index>=shape[0] for index in freeze['inputs']):
|
| 119 |
+
raise ValueError('Frozen input exceeds sensor count')
|
| 120 |
+
if any(index>=shape[-1] for index in freeze['outputs']):
|
| 121 |
+
raise ValueError('Frozen output exceeds output count')
|
| 122 |
+
layers=set(freeze['layers']);inputs=set(freeze['inputs']);outputs=set(freeze['outputs'])
|
| 123 |
+
trainable=0
|
| 124 |
+
last=len(shape)-2
|
| 125 |
+
for layer,(source_count,dest_count) in enumerate(zip(shape,shape[1:])):
|
| 126 |
+
for source in range(source_count):
|
| 127 |
+
for dest in range(dest_count):
|
| 128 |
+
if not (layer+1 in layers or layer==0 and source in inputs or layer==last and dest in outputs):
|
| 129 |
+
trainable+=1
|
| 130 |
+
for dest in range(dest_count):
|
| 131 |
+
if not (layer+1 in layers or layer==last and dest in outputs):
|
| 132 |
+
trainable+=1
|
| 133 |
+
if not trainable:
|
| 134 |
+
raise ValueError('Freeze selection leaves no trainable parameters; use frozen evaluation')
|
| 135 |
+
|
| 136 |
+
def verify_frozen_parameters(freeze,starting,trained):
|
| 137 |
+
"""Never publish a result whose native candidate violates the requested mask."""
|
| 138 |
+
layers=set(freeze['layers']);inputs=set(freeze['inputs']);outputs=set(freeze['outputs'])
|
| 139 |
+
last=len(starting['Shape'])-2
|
| 140 |
+
for layer,matrix in enumerate(starting['Weights']):
|
| 141 |
+
for source,row in enumerate(matrix):
|
| 142 |
+
for dest,value in enumerate(row):
|
| 143 |
+
if (layer+1 in layers or layer==0 and source in inputs or layer==last and dest in outputs):
|
| 144 |
+
if value!=trained['weights'][layer][source][dest]:
|
| 145 |
+
raise ValueError('Native trainer changed a frozen weight')
|
| 146 |
+
for dest,value in enumerate(starting['Biases'][layer]):
|
| 147 |
+
if layer+1 in layers or layer==last and dest in outputs:
|
| 148 |
+
if value!=trained['biases'][layer][dest]:
|
| 149 |
+
raise ValueError('Native trainer changed a frozen bias')
|
| 150 |
+
|
| 151 |
def track_input(data):
|
| 152 |
value=read_json(data)
|
| 153 |
challenges=value.get('Challenges',[])
|
|
|
|
| 206 |
if not needs_observations(track,track_sha):
|
| 207 |
return resolve_check(track,template,config,[],**kwargs)
|
| 208 |
check_command=list(command)
|
| 209 |
+
if '--freeze-spec' in check_command:
|
| 210 |
+
index=check_command.index('--freeze-spec')
|
| 211 |
+
del check_command[index:index+2]
|
| 212 |
def option(name,value):
|
| 213 |
check_command[check_command.index(name)+1]=str(value)
|
| 214 |
n=template['NeuralNetwork']
|
|
|
|
| 250 |
started=time.perf_counter()
|
| 251 |
config=validate_config(config)
|
| 252 |
track=track_input(track_bytes); template=network_input(network_bytes)
|
| 253 |
+
if config['mode']=='train':check_freeze_shape(config['freeze'],template['NeuralNetwork']['Shape'])
|
| 254 |
# Deployment paths are supplied by trusted application configuration, never uploads.
|
| 255 |
binary=Path(binary or ROOT/'target/release/altd-sim').resolve()
|
| 256 |
importer=Path(importer or ROOT/'target/release/examples/extract_saved_track').resolve()
|
|
|
|
| 289 |
'--checkpoint-every','0','--analysis','--clean-min-laps',str(config['clean_min_laps']),
|
| 290 |
'--eliminate-on-wall' if config['collision'] else '--no-eliminate-on-wall',
|
| 291 |
'--idle-eliminate' if config['idle'] else '--no-idle-eliminate']
|
| 292 |
+
if config['mode']=='train' and any(config['freeze'].values()):
|
| 293 |
+
command.extend(('--freeze-spec',save('freeze.json',config['freeze'])))
|
| 294 |
if config['mode']=='evaluate':command.append('--evaluate-frozen')
|
| 295 |
if gpu_library is not None: command.append('--gpu')
|
| 296 |
subprocess.run(command,cwd=work,env=env,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=25,check=True)
|
|
|
|
| 298 |
candidate=out/'candidate.json'
|
| 299 |
if candidate.stat().st_size>1024*1024: raise ValueError('Output too large')
|
| 300 |
trained=json.loads(candidate.read_text())
|
| 301 |
+
if any(config['freeze'].values()):verify_frozen_parameters(config['freeze'],n,trained)
|
| 302 |
n['Weights']=trained['weights']; n['Biases']=trained['biases']
|
| 303 |
result=(network_bytes if config['mode']=='evaluate' else gzip.compress(json.dumps(template,allow_nan=False).encode(),mtime=0))
|
| 304 |
network_input(result)
|