v0.9.0: análise/prova/teste das críticas de arquitetura Qwen3.8 (r-34) — skew O(n²) via index_add (919× n=128, memória 2335×, bit-a-bit F-13/F-14), calibrar zero-cópia (1,56×, F-15; premissa SIMD refutada no fonte do candle), forward canônico (bug v080-1 fora da API pública, oráculos preservados), FFI isolada em feature python (lib.rs 105kB→1,25kB; 107/107 sem Python; overhead medido 17,6%), newtypes T-V1/T-V2 — 97/97 gates, treino real Wikipédia PT-BR
Browse files- Cargo.lock +1 -102
- Cargo.toml +13 -12
- README.md +16 -5
- dados/shard_treino.jsonl +0 -0
- dados/shard_validacao.jsonl +27 -0
- docs/memorias/r-34-analise-provas-qwen-v090.md +405 -0
- pyproject.toml +3 -3
- resultados/gerador_conceitos.json +3 -0
- resultados/suite_v090_final.json +159 -0
- resultados/telemetria_fase_c.jsonl +0 -0
- resultados/telemetria_v090.json +91 -0
- resultados/tokenizador_conceitos.json +3 -0
- resultados/treino_v090.json +192 -0
- scripts/70_coleta_shards_v090.py +53 -0
- scripts/71_treino_v090.py +169 -0
- scripts/72_suite_v090.py +125 -0
- scripts/73_telemetria_v090.py +82 -0
- scripts/74_publicar_v090.py +168 -0
- src/fnh.rs +350 -3
- src/lib.rs +0 -0
- src/moe_redirecionavel.rs +31 -26
- src/python.rs +0 -0
- src/tipos.rs +120 -0
- src/treino.rs +12 -11
Cargo.lock
CHANGED
|
@@ -302,17 +302,6 @@ dependencies = [
|
|
| 302 |
"syn 2.0.119",
|
| 303 |
]
|
| 304 |
|
| 305 |
-
[[package]]
|
| 306 |
-
name = "dict_derive"
|
| 307 |
-
version = "0.5.1"
|
| 308 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 309 |
-
checksum = "846a520b3b7937dcfe564d9674d2d26da9e3cd0f8f1bbef51ca42fd6b7bb4f4a"
|
| 310 |
-
dependencies = [
|
| 311 |
-
"proc-macro2",
|
| 312 |
-
"quote",
|
| 313 |
-
"syn 1.0.109",
|
| 314 |
-
]
|
| 315 |
-
|
| 316 |
[[package]]
|
| 317 |
name = "dyn-stack"
|
| 318 |
version = "0.13.2"
|
|
@@ -734,19 +723,16 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
|
| 734 |
|
| 735 |
[[package]]
|
| 736 |
name = "khtst-rust"
|
| 737 |
-
version = "0.
|
| 738 |
dependencies = [
|
| 739 |
"anyhow",
|
| 740 |
"built",
|
| 741 |
"candle-core",
|
| 742 |
"candle-nn",
|
| 743 |
"crossbeam-channel",
|
| 744 |
-
"dict_derive",
|
| 745 |
"log",
|
| 746 |
-
"numpy",
|
| 747 |
"pyo3",
|
| 748 |
"pyo3-async-runtimes",
|
| 749 |
-
"pyo3-built",
|
| 750 |
"pyo3-log",
|
| 751 |
"pythonize",
|
| 752 |
"rand 0.8.8",
|
|
@@ -797,16 +783,6 @@ version = "0.2.3"
|
|
| 797 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 798 |
checksum = "fc04a4c58212d57930a24bf47d3fa87485264a3a054e9c10e042eb373573ad3c"
|
| 799 |
|
| 800 |
-
[[package]]
|
| 801 |
-
name = "matrixmultiply"
|
| 802 |
-
version = "0.3.11"
|
| 803 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 804 |
-
checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7"
|
| 805 |
-
dependencies = [
|
| 806 |
-
"autocfg",
|
| 807 |
-
"rawpointer",
|
| 808 |
-
]
|
| 809 |
-
|
| 810 |
[[package]]
|
| 811 |
name = "memchr"
|
| 812 |
version = "2.8.3"
|
|
@@ -860,21 +836,6 @@ dependencies = [
|
|
| 860 |
"syn 2.0.119",
|
| 861 |
]
|
| 862 |
|
| 863 |
-
[[package]]
|
| 864 |
-
name = "ndarray"
|
| 865 |
-
version = "0.16.1"
|
| 866 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 867 |
-
checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
|
| 868 |
-
dependencies = [
|
| 869 |
-
"matrixmultiply",
|
| 870 |
-
"num-complex",
|
| 871 |
-
"num-integer",
|
| 872 |
-
"num-traits",
|
| 873 |
-
"portable-atomic",
|
| 874 |
-
"portable-atomic-util",
|
| 875 |
-
"rawpointer",
|
| 876 |
-
]
|
| 877 |
-
|
| 878 |
[[package]]
|
| 879 |
name = "nom"
|
| 880 |
version = "7.1.3"
|
|
@@ -895,15 +856,6 @@ dependencies = [
|
|
| 895 |
"num-traits",
|
| 896 |
]
|
| 897 |
|
| 898 |
-
[[package]]
|
| 899 |
-
name = "num-integer"
|
| 900 |
-
version = "0.1.47"
|
| 901 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 902 |
-
checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b"
|
| 903 |
-
dependencies = [
|
| 904 |
-
"num-traits",
|
| 905 |
-
]
|
| 906 |
-
|
| 907 |
[[package]]
|
| 908 |
name = "num-traits"
|
| 909 |
version = "0.2.19"
|
|
@@ -924,21 +876,6 @@ dependencies = [
|
|
| 924 |
"libc",
|
| 925 |
]
|
| 926 |
|
| 927 |
-
[[package]]
|
| 928 |
-
name = "numpy"
|
| 929 |
-
version = "0.23.0"
|
| 930 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 931 |
-
checksum = "b94caae805f998a07d33af06e6a3891e38556051b8045c615470a71590e13e78"
|
| 932 |
-
dependencies = [
|
| 933 |
-
"libc",
|
| 934 |
-
"ndarray",
|
| 935 |
-
"num-complex",
|
| 936 |
-
"num-integer",
|
| 937 |
-
"num-traits",
|
| 938 |
-
"pyo3",
|
| 939 |
-
"rustc-hash",
|
| 940 |
-
]
|
| 941 |
-
|
| 942 |
[[package]]
|
| 943 |
name = "once_cell"
|
| 944 |
version = "1.21.4"
|
|
@@ -997,15 +934,6 @@ version = "1.15.0"
|
|
| 997 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 998 |
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
| 999 |
|
| 1000 |
-
[[package]]
|
| 1001 |
-
name = "portable-atomic-util"
|
| 1002 |
-
version = "0.2.8"
|
| 1003 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1004 |
-
checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715"
|
| 1005 |
-
dependencies = [
|
| 1006 |
-
"portable-atomic",
|
| 1007 |
-
]
|
| 1008 |
-
|
| 1009 |
[[package]]
|
| 1010 |
name = "ppv-lite86"
|
| 1011 |
version = "0.2.21"
|
|
@@ -1088,12 +1016,6 @@ dependencies = [
|
|
| 1088 |
"target-lexicon",
|
| 1089 |
]
|
| 1090 |
|
| 1091 |
-
[[package]]
|
| 1092 |
-
name = "pyo3-built"
|
| 1093 |
-
version = "0.5.0"
|
| 1094 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1095 |
-
checksum = "35ee655adc94166665a1d714b439e27857dd199b947076891d6a17d32d396cde"
|
| 1096 |
-
|
| 1097 |
[[package]]
|
| 1098 |
name = "pyo3-ffi"
|
| 1099 |
version = "0.23.5"
|
|
@@ -1249,12 +1171,6 @@ dependencies = [
|
|
| 1249 |
"bitflags",
|
| 1250 |
]
|
| 1251 |
|
| 1252 |
-
[[package]]
|
| 1253 |
-
name = "rawpointer"
|
| 1254 |
-
version = "0.2.1"
|
| 1255 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1256 |
-
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
| 1257 |
-
|
| 1258 |
[[package]]
|
| 1259 |
name = "rayon"
|
| 1260 |
version = "1.12.0"
|
|
@@ -1321,12 +1237,6 @@ version = "0.8.11"
|
|
| 1321 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1322 |
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
| 1323 |
|
| 1324 |
-
[[package]]
|
| 1325 |
-
name = "rustc-hash"
|
| 1326 |
-
version = "2.1.3"
|
| 1327 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1328 |
-
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
| 1329 |
-
|
| 1330 |
[[package]]
|
| 1331 |
name = "rustix"
|
| 1332 |
version = "1.1.5"
|
|
@@ -1471,17 +1381,6 @@ version = "0.11.1"
|
|
| 1471 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1472 |
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
| 1473 |
|
| 1474 |
-
[[package]]
|
| 1475 |
-
name = "syn"
|
| 1476 |
-
version = "1.0.109"
|
| 1477 |
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1478 |
-
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
| 1479 |
-
dependencies = [
|
| 1480 |
-
"proc-macro2",
|
| 1481 |
-
"quote",
|
| 1482 |
-
"unicode-ident",
|
| 1483 |
-
]
|
| 1484 |
-
|
| 1485 |
[[package]]
|
| 1486 |
name = "syn"
|
| 1487 |
version = "2.0.119"
|
|
|
|
| 302 |
"syn 2.0.119",
|
| 303 |
]
|
| 304 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
[[package]]
|
| 306 |
name = "dyn-stack"
|
| 307 |
version = "0.13.2"
|
|
|
|
| 723 |
|
| 724 |
[[package]]
|
| 725 |
name = "khtst-rust"
|
| 726 |
+
version = "0.9.0"
|
| 727 |
dependencies = [
|
| 728 |
"anyhow",
|
| 729 |
"built",
|
| 730 |
"candle-core",
|
| 731 |
"candle-nn",
|
| 732 |
"crossbeam-channel",
|
|
|
|
| 733 |
"log",
|
|
|
|
| 734 |
"pyo3",
|
| 735 |
"pyo3-async-runtimes",
|
|
|
|
| 736 |
"pyo3-log",
|
| 737 |
"pythonize",
|
| 738 |
"rand 0.8.8",
|
|
|
|
| 783 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 784 |
checksum = "fc04a4c58212d57930a24bf47d3fa87485264a3a054e9c10e042eb373573ad3c"
|
| 785 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 786 |
[[package]]
|
| 787 |
name = "memchr"
|
| 788 |
version = "2.8.3"
|
|
|
|
| 836 |
"syn 2.0.119",
|
| 837 |
]
|
| 838 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 839 |
[[package]]
|
| 840 |
name = "nom"
|
| 841 |
version = "7.1.3"
|
|
|
|
| 856 |
"num-traits",
|
| 857 |
]
|
| 858 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 859 |
[[package]]
|
| 860 |
name = "num-traits"
|
| 861 |
version = "0.2.19"
|
|
|
|
| 876 |
"libc",
|
| 877 |
]
|
| 878 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 879 |
[[package]]
|
| 880 |
name = "once_cell"
|
| 881 |
version = "1.21.4"
|
|
|
|
| 934 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 935 |
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
|
| 936 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 937 |
[[package]]
|
| 938 |
name = "ppv-lite86"
|
| 939 |
version = "0.2.21"
|
|
|
|
| 1016 |
"target-lexicon",
|
| 1017 |
]
|
| 1018 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1019 |
[[package]]
|
| 1020 |
name = "pyo3-ffi"
|
| 1021 |
version = "0.23.5"
|
|
|
|
| 1171 |
"bitflags",
|
| 1172 |
]
|
| 1173 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1174 |
[[package]]
|
| 1175 |
name = "rayon"
|
| 1176 |
version = "1.12.0"
|
|
|
|
| 1237 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1238 |
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
| 1239 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1240 |
[[package]]
|
| 1241 |
name = "rustix"
|
| 1242 |
version = "1.1.5"
|
|
|
|
| 1381 |
source = "registry+https://github.com/rust-lang/crates.io-index"
|
| 1382 |
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
| 1383 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1384 |
[[package]]
|
| 1385 |
name = "syn"
|
| 1386 |
version = "2.0.119"
|
Cargo.toml
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
[package]
|
| 2 |
name = "khtst-rust"
|
| 3 |
-
version = "0.
|
| 4 |
edition = "2021"
|
| 5 |
-
description = "KHTST_RUST —
|
| 6 |
license = "Apache-2.0"
|
| 7 |
|
| 8 |
[lib]
|
|
@@ -10,14 +10,7 @@ name = "khtst_rust"
|
|
| 10 |
crate-type = ["cdylib", "rlib"]
|
| 11 |
|
| 12 |
[dependencies]
|
| 13 |
-
|
| 14 |
-
numpy = "0.23"
|
| 15 |
-
pythonize = "0.23"
|
| 16 |
-
pyo3-log = "0.12"
|
| 17 |
-
dict_derive = "0.5"
|
| 18 |
-
pyo3-built = "0.5"
|
| 19 |
-
pyo3-async-runtimes = { version = "0.23", optional = true, features = ["tokio-runtime"] }
|
| 20 |
-
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
| 21 |
candle-core = "0.11"
|
| 22 |
candle-nn = "0.11"
|
| 23 |
crossbeam-channel = "0.5"
|
|
@@ -29,12 +22,20 @@ thiserror = "2"
|
|
| 29 |
log = "0.4"
|
| 30 |
rand = "0.8"
|
| 31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
[build-dependencies]
|
| 33 |
built = "0.8"
|
| 34 |
|
| 35 |
[features]
|
| 36 |
-
default = ["ponte_async"]
|
| 37 |
-
|
|
|
|
| 38 |
|
| 39 |
[profile.release]
|
| 40 |
opt-level = 3
|
|
|
|
| 1 |
[package]
|
| 2 |
name = "khtst-rust"
|
| 3 |
+
version = "0.9.0"
|
| 4 |
edition = "2021"
|
| 5 |
+
description = "KHTST_RUST — análise/prova/teste das críticas Qwen3.8 v2 (r-34): skew O(n²) diferenciável via index_add, calibrar vetorial bit-a-bit, forward canônico (bug v080-1 fora da API pública), FFI isolada em feature python, newtypes de domínio"
|
| 6 |
license = "Apache-2.0"
|
| 7 |
|
| 8 |
[lib]
|
|
|
|
| 10 |
crate-type = ["cdylib", "rlib"]
|
| 11 |
|
| 12 |
[dependencies]
|
| 13 |
+
# --- domínio (compilam SEM Python: cargo test --no-default-features) ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
candle-core = "0.11"
|
| 15 |
candle-nn = "0.11"
|
| 16 |
crossbeam-channel = "0.5"
|
|
|
|
| 22 |
log = "0.4"
|
| 23 |
rand = "0.8"
|
| 24 |
|
| 25 |
+
# --- FFI Python (feature "python" — v0.9.0: opcional, era incondicional) ---
|
| 26 |
+
pyo3 = { version = "0.23", features = ["abi3-py310"], optional = true }
|
| 27 |
+
pythonize = { version = "0.23", optional = true }
|
| 28 |
+
pyo3-log = { version = "0.12", optional = true }
|
| 29 |
+
pyo3-async-runtimes = { version = "0.23", optional = true, features = ["tokio-runtime"] }
|
| 30 |
+
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
| 31 |
+
|
| 32 |
[build-dependencies]
|
| 33 |
built = "0.8"
|
| 34 |
|
| 35 |
[features]
|
| 36 |
+
default = ["python", "ponte_async"]
|
| 37 |
+
python = ["dep:pyo3", "dep:pythonize", "dep:pyo3-log"]
|
| 38 |
+
ponte_async = ["python", "dep:pyo3-async-runtimes", "dep:tokio"]
|
| 39 |
|
| 40 |
[profile.release]
|
| 41 |
opt-level = 3
|
README.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
| 1 |
-
# KHTST_RUST v0.
|
| 2 |
-
|
| 3 |
-
> **v0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
> do Pensamento (V-1..V-4 — soundness sem acesso ao alvo), **treino conjunto
|
| 5 |
> Pensamento↔backbone** (fase C: gradiente bidirecional, PCGrad, acoplador
|
| 6 |
> duplex AC-1..AC-3), **MoEs de codificação/decodificação redirecionáveis com
|
|
@@ -8,8 +21,6 @@
|
|
| 8 |
> (M-R1..M-R5), e **autoajuste por telemetria** de todos os hiperparâmetros
|
| 9 |
> do Pensamento (A-1..A-5) com **seleção de arquitetura por UCB1** e loop
|
| 10 |
> iterativo com parada marginal. Provas: `docs/memorias/r-23…r-27`.
|
| 11 |
-
> Veredito consolidado: **46/46 gates verdes** (script 59) + **54/54 testes
|
| 12 |
-
> cargo**.
|
| 13 |
|
| 14 |
Refatoração completa do projeto **KHTST** (`PowerMachine/khtst-multimodal-ptbr`) para **Rust** via **PyO3**, integrando o paradigma **NCM (Next-Concept Modeling)** com todas as provas matemáticas da coleção `memoria-ncm-khtst`, ADBA (atenção adaptativa no processamento paralelo) e Ponte Duplex (comunicação bidirecional simultânea entre modelos).
|
| 15 |
|
|
|
|
| 1 |
+
# KHTST_RUST v0.9.0 — Críticas Qwen3.8 Analisadas/Provadas/Testadas + Domínio sem FFI
|
| 2 |
+
|
| 3 |
+
> **v0.9.0 (este ciclo)**: segundo lote de críticas do agente Qwen3.8
|
| 4 |
+
> (arquitetura/complexidade) analisado, provado e testado em `r-34`:
|
| 5 |
+
> **skew O(n²) diferenciável** via `index_add` (919× mais rápido em n=128,
|
| 6 |
+
> memória 2.335× menor, bit-a-bit — F-13/F-14), **calibrar zero-cópia**
|
| 7 |
+
> (1,56×, bit-a-bit, com a premissa "kernels SIMD" REFUTADA na CPU por
|
| 8 |
+
> análise do kernel do candle — F-15), **`forward` canônico** (bug v080-1
|
| 9 |
+
> fora da superfície pública; oráculos preservados), **FFI isolada em
|
| 10 |
+
> `feature = "python"`** (lib.rs 105 kB → 1,25 kB; `cargo test
|
| 11 |
+
> --no-default-features` roda 107/107 SEM Python; overhead medido 17,6%),
|
| 12 |
+
> **newtypes de domínio** com construtores validados (T-V1/T-V2 — errata
|
| 13 |
+
> da proposta `pub struct P(pub f64)`). **97/97 gates** (85 herdados +
|
| 14 |
+
> 12 novos) + treino REAL Wikipédia PT-BR íntegro no build v0.9.0.
|
| 15 |
+
|
| 16 |
+
> **v0.6.0**: **verificador NCM calibrado** substitui o oráculo
|
| 17 |
> do Pensamento (V-1..V-4 — soundness sem acesso ao alvo), **treino conjunto
|
| 18 |
> Pensamento↔backbone** (fase C: gradiente bidirecional, PCGrad, acoplador
|
| 19 |
> duplex AC-1..AC-3), **MoEs de codificação/decodificação redirecionáveis com
|
|
|
|
| 21 |
> (M-R1..M-R5), e **autoajuste por telemetria** de todos os hiperparâmetros
|
| 22 |
> do Pensamento (A-1..A-5) com **seleção de arquitetura por UCB1** e loop
|
| 23 |
> iterativo com parada marginal. Provas: `docs/memorias/r-23…r-27`.
|
|
|
|
|
|
|
| 24 |
|
| 25 |
Refatoração completa do projeto **KHTST** (`PowerMachine/khtst-multimodal-ptbr`) para **Rust** via **PyO3**, integrando o paradigma **NCM (Next-Concept Modeling)** com todas as provas matemáticas da coleção `memoria-ncm-khtst`, ADBA (atenção adaptativa no processamento paralelo) e Ponte Duplex (comunicação bidirecional simultânea entre modelos).
|
| 26 |
|
dados/shard_treino.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
dados/shard_validacao.jsonl
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"texto": "Astronomia é uma ciência natural que estuda corpos celestes (como estrelas, planetas, cometas, nebulosas, aglomerados de estrelas, galáxias) e fenômenos que se originam fora da atmosfera da Terra (como a radiação cósmica de fundo em micro-ondas). Preocupada com a evolução, a física e a química de objetos celestes, bem como a formação e o desenvolvimento do universo. A astronomia é uma das mais antigas ciências. Culturas pré-históricas deixaram registrados vários artefatos astronômicos, como Stonehenge, os montes de Newgrange e os menires. As primeiras civilizações, como os babilônios, gregos, chineses, indianos, persas e maias realizaram observações metódicas do céu noturno. No entanto, a invenção do telescópio permitiu o desenvolvimento da astronomia moderna. Historicamente, a astronomia incluiu disciplinas tão diversas como astrometria, navegação astronômica, astronomia observacional e a elaboração de calendários. Durante o período medieval, seu estudo era obrigatório e estava incluído no Quadrivium que, junto com o Trivium, compunha a metodologia de ensino das sete Artes liberais. Durante o século XX, o campo da astronomia profissional dividiu-se em dois ramos: a astronomia observacional e a astronomia teórica. A primeira está focada na aquisição de dados a partir da observação de objetos celestes, que são então analisados utilizando os princípios básicos da física. Já a segunda é orientada para o desenvolvimento de modelos analíticos que descrevem objetos e fenômenos astronômicos. Os dois campos se complementam, com a astronomia teórica procurando explicar os resultados observacionais, bem com as observações sendo usadas para confirmar (ou não) os resultados teóricos. Os astrônomos amadores têm contribuído para muitas e importantes descobertas astronômicas. A astron"}
|
| 2 |
+
{"texto": "A América Latina (; ) é uma região do continente americano que engloba os países onde são faladas, primordialmente, línguas românicas (derivadas do latim) — no caso, o espanhol, o português e o francês — visto que, historicamente, a região foi maioritariamente dominada pelos impérios coloniais europeus Espanhol e Português. A América Latina tem uma área de cerca de km², o equivalente a cerca de 3,9% da superfície da Terra (ou 14,1% de sua superfície emersa terrestre). Em 2008, a sua população foi estimada em mais de 569 milhões de pessoas. Os países do restante do continente americano tiveram uma colonização majoritariamente realizada por povos europeus de cultura anglo-saxônica ou neerlandesa (ver América Anglo-Saxônica). Vale ressaltar algumas exceções, como Québec, que não é um país independente, mas uma província de maioria francófona que pertence ao Canadá; o estado da Luisiana, que também foi colonizado por franceses, mas pertence aos Estados Unidos e os estados do sudoeste estadunidense, que tiveram colonização espanhola. A América Latina compreende a quase totalidade das Américas do Sul e Central: as exceções são os países sul-americanos da Guiana e do Suriname e a nação centro-americana de Belize e da Jamaica, que são países de línguas germânicas. Também engloba alguns países da América Central Insular (países compostos de ilhas e arquipélagos banhados pelo Mar do Caribe), como Cuba, República Dominicana e Haiti. Da América do Norte, apenas o México é considerado como parte da América Latina. A região engloba 20 países: Argentina, Bolívia, Brasil, Chile, Colômbia, Costa Rica, Cuba, Equador, El Salvador, Guatemala, Haiti, Honduras, México, Nicarágua, Panamá, Paraguai, Peru, República Dominicana, Uruguai e Venezuela. A expressão \"América Latina\" foi utilizada pe"}
|
| 3 |
+
{"texto": "Albino Maria Pereira Forjaz de Sampaio (Lisboa, 19 de Janeiro de 1884 — Lisboa, 13 de Março de 1949) foi um escritor e bibliógrafo português, autor de um dos livros mais vendidos em Portugal durante o século XX, Palavras Cínicas, lançado em 1905, que à morte do autor tinha já 46 edições. Albino Forjaz de Sampaio começou a sua carreira literária aos 16 anos como jornalista no jornal A Lucta sob o patronato de Fialho de Almeida e Brito Camacho. O seu percurso teve duas fases distintas, um pouco como a sua escrita. Se de início a sua escrita aprendeu muito do jornalismo, o falar da rua, do submundo lisboeta, a resposta rápida, numa segunda fase procurou legitimar essas características com formas arcaicas e coloquialismos de origem erudita que foi encontrar nas suas investigações sobre o antigo teatro popular. A crónica de crítica social que procurava inverter a moral comum da época tornou-o famoso sobretudo pelo escândalo que as suas opiniões originavam. Fazia-o um pouco à maneira de Oscar Wilde mas num país ainda menos preparado para tais agitações. Daí que a sua estreia tenha sido estrondosa (embora as crónicas jornalísticas que já publicara o anunciassem), com o livro Palavras Cínicas que, no começo do século (1905), deixava os portugueses tudo menos indiferentes: muitos criticaram, outros riram, alguns elogiaram. Neste livro Sampaio tentava subverter a moral vigente, emitindo juízos anticlericais, contra a crendice popular, e a \"esperteza\" saloia, e deixando clara a sua opinião de que a vida não vale a pena no mundo em que se vivia. A partir deste sucesso, Forjaz de Sampaio levou a sua crítica social ao ponto de criar uma arte da crítica ou, como o poria Wilde, a crítica pela crítica. Com humor, cinismo e uma ausência completa de consciência social a obra de Forjaz de "}
|
| 4 |
+
{"texto": "Anno Domini (A.D.) é uma expressão em latim que significa \"no ano do Senhor\" e é utilizada para marcar os anos seguintes ao ano 1 do calendário mais comumente utilizado no Ocidente, designado como \"Era Cristã\" ou, ainda, como \"Era Comum\". Aparecia em inscrições latinas e ainda é usada na língua inglesa, correspondendo à expressão \"depois de Cristo\" (DC, D.C. ou d.C.) e em sucessão ao período \"antes de Cristo\" (AC, A.C. ou a.C.). Esta era cronológica (\"Era Cristã\" ou \"Era Comum\"), que é globalmente adotada, mesmo em países de cultura maioritariamente não cristã, para efeitos de unanimidade de critérios em vários âmbitos, como o científico e comercial, foi organizada de forma a contar o ano do nascimento de Cristo como ano 1, marcando uma linha divisória no tempo a partir de então. A contagem dos anos assemelha-se à ordem dos números inteiros (com a exceção de que não existiu um ano zero - pelo que o ano foi imediatamente sucedido pelo ano ), pelo que também é comum referir os anos antes de Cristo por números inteiros negativos e os anos depois de Cristo por números inteiros positivos. Utiliza-se, nesta forma de datação, os calendários Juliano e Gregoriano. O termo Anno Domini é, por vezes, substituído pela expressão mais formal e descritiva Anno Domini Nostri Iesu Christi (\"Ano de Nosso Senhor Jesus Cristo\"). É, por vezes, ainda substituído pela expressão na era da Graça. A forma de datação segundo o Anno Domini foi primeiramente utilizada na Europa Ocidental durante o . Portugal foi um dos últimos países a adotar o novo método, imposto pelo rei Dom João I, a 15 de Agosto de 1422, em substituição da \"era de César\". A Espanha já o usava desde meados do século precedente. Nem todos os países seguem o calendário ocidental: judeus e muçulmanos, por exemplo, organizam anos e"}
|
| 5 |
+
{"texto": "Aquiles (), na mitologia grega, foi um herói da Grécia, um dos participantes da Guerra de Troia e o protagonista e maior guerreiro da Ilíada, de Homero. Aquiles tem ainda a característica de ser loiro e o mais belo dos heróis reunidos contra Troia, assim como o melhor entre eles. A figura de Aquiles foi sendo moldada por diversos autores num espaço de mil anos, o que explica suas diversas contradições. A mais conhecida é a que fala que Aquiles era invulnerável em todo o seu corpo por se banhar no rio Estige, exceto em seu calcanhar (conforme um poema de Estácio, no ). Segundo estas versões de seu mito, sua morte teria sido causada por uma flecha envenenada que o teria atingido exatamente nesta parte de seu corpo, desprotegida da armadura. A expressão \"calcanhar de Aquiles\", que indica a principal fraqueza de alguém, teria aí a sua origem. As obras literárias (e artísticas em geral) em que Aquiles aparece como herói são abundantes. Para além da Ilíada e da Odisseia - onde é mostrada o destino de Aquiles após a sua morte - pode-se destacar, ainda, a tragédia Ifigénia em Áulide, de Eurípides, \"imitada\" mais tarde pelo dramaturgo francês Jean Racine (1674) e transformada em ópera pelo compositor alemão Christoph Willibald Gluck (1774), além das artes plásticas, onde podem ser encontradas, além das diversas pinturas de vasos e esculturas do próprio período da Antiguidade Clássica, telas de Peter Paul Rubens, David Teniers, o Jovem, Jean-Auguste Dominique Ingres, Eugène Delacroix e muitos outros, que retratam as suas múltiplas façanhas. O nome de Aquiles pode ser interpretado como uma combinação de ἄχος (achos), \"luto\" e λαός (laos), \"povo\", \"tribo\", \"nação\", etc. Em outras palavras, Aquiles seria uma personificação do luto das pessoas, luto sendo um dos temas que é levantado"}
|
| 6 |
+
{"texto": "Anarcocapitalismo (também conhecido como anarquismo de livre mercado ou anarquismo de propriedade privada) é uma filosofia política libertária que defende o direito a soberania do indivíduo através da propriedade privada e do livre mercado. Os anarcocapitalistas buscam abolir os estados centralizados em favor de sociedades sem estado com sistemas de propriedade privada aplicados por agências privadas, pelo princípio da não agressão, por livres mercados e sob a interpretação libertária capitalista de autopropriedade. Os anarcocapitalistas sustentam que a sociedade tende a se autorregular e civilizar contratualmente através da participação no livre mercado, que eles descrevem como uma sociedade voluntária envolvendo a troca voluntária de serviços e bens. Em uma sociedade anarcocapitalista, o sistema de propriedade privada ainda existiria e seria aplicado por agências privadas de defesa e/ou seguradoras selecionadas por clientes que operariam competitivamente em um mercado e cumpririam os papéis dos tribunais e da polícia. O dinheiro e as moedas correntes seriam fornecidos de forma privada e competitiva num mercado aberto, através de um sistema bancário livre. Desta forma, as atividades pessoais e econômicas do anarcocapitalismo seriam reguladas através de gestão e direito privado. O anarcocapitalismo é geralmente visto como parte do movimento social da Nova Direita. A sociedade anarcocapitalista operaria sob \"um código legal que seja aceito em termos gerais, e que os tribunais se comprometeriam a respeitar. O código legal justamente insistiria no princípio libertário de que nenhuma agressão deve ser cometida contra pessoa ou propriedade, definiria os direitos de propriedade de acordo com o princípio libertário, e estabeleceria as regras de evidência (tais como código lega"}
|
| 7 |
+
{"texto": "Anarquismo é uma ideologia política que se opõe a todo tipo de hierarquia e dominação, seja ela política, econômica, social ou cultural, como o Estado, o capitalismo, as instituições religiosas, o racismo e o patriarcado. Através de uma análise crítica da dominação, o anarquismo pretende superar a ordem social na qual esta se faz presente através de um projeto construtivo baseado na defesa da autogestão, tendo em vista a constituição de uma sociedade libertária baseada na cooperação e na ajuda mútua entre os indivíduos e onde estes possam associar-se livremente. Os meios para se alcançar tais objetivos são motivos de debates e divergências entre os anarquistas. Com base em discussões estratégicas acerca da organização anarquista, das lutas de curto prazo e da violência, estabelecem-se duas correntes do anarquismo: o anarquismo insurrecionário e o anarquismo social ou de massas. O anarquismo insurrecionário afirma que as lutas de curto prazo por reformas e que os movimentos de massa organizados são incompatíveis com o anarquismo, dando ênfase à propaganda pelo ato como o principal meio para despertar uma revolta espontânea revolucionária. Já o anarquismo social ou de massas enfatiza a noção de que apenas movimentos de massa podem ser capazes de provocar a transformação social desejada pelos anarquistas, e que tais movimentos, constituídos normalmente por meio de lutas por reformas e questões imediatas, devem contar com a presença dos anarquistas, que devem trabalhar no sentido de radicalizá-los e transformá-los em agentes revolucionários. Historicamente, o anarquismo é um fenômeno moderno, surgindo na segunda metade do no contexto da Segunda Revolução Industrial, a partir da radicalização do mutualismo de Pierre-Joseph Proudhon no seio da Associação Internacional dos "}
|
| 8 |
+
{"texto": "Albert Einstein (Ulm, 14 de março de 1879 – Princeton, 18 de abril de 1955) foi um físico teórico alemão, que desenvolveu a teoria da relatividade geral, um dos pilares da física moderna ao lado da mecânica quântica. Embora mais conhecido por sua fórmula de equivalência massa-energia, E = mc² — que foi chamada de \"a equação mais famosa do mundo\" —, foi laureado com o Prêmio Nobel de Física de 1921 \"por suas contribuições à física teórica\" e, especialmente, por sua descoberta da lei do efeito fotoelétrico, que foi fundamental no estabelecimento da teoria quântica. Nascido em uma família de judeus alemães, mudou-se para a Suíça ainda jovem e iniciou seus estudos na Escola Politécnica de Zurique. Após dois anos procurando emprego, obteve um cargo no escritório de patentes suíço enquanto ingressava no curso de doutorado da Universidade de Zurique. Em 1905, publicou uma série de artigos acadêmicos revolucionários. Uma de suas obras era o desenvolvimento da teoria da relatividade especial. Percebeu, no entanto, que o princípio da relatividade também poderia ser estendido para campos gravitacionais, e com a sua posterior teoria da gravitação, de 1916, publicou um artigo sobre a teoria da relatividade geral. Enquanto acumulava cargos em universidades e instituições, continuou a lidar com problemas da mecânica estatística e teoria quântica, o que levou às suas explicações sobre a teoria das partículas e o movimento browniano. Também investigou as propriedades térmicas da luz, o que lançou as bases da teoria dos fótons. Em 1917, aplicou a teoria da relatividade geral para modelar a estrutura do universo como um todo. Suas obras renderam-lhe o status de celebridade mundial enquanto tornava-se uma nova figura na história da humanidade, recebendo prêmios internacionais e sendo convi"}
|
| 9 |
+
{"texto": "Aquecimento global é o processo de aumento da temperatura média dos oceanos e da atmosfera da Terra causado por massivas emissões de gases que intensificam o efeito estufa, originados de uma série de atividades humanas, especialmente a queima de combustíveis fósseis e mudanças no uso da terra, como o desmatamento, bem como de várias outras fontes secundárias. Essas causas são um produto direto da explosão populacional, do crescimento econômico, do uso de tecnologias e fontes de energia poluidoras e de um estilo de vida insustentável, em que a natureza é vista como matéria-prima para exploração. Os principais gases do efeito estufa emitidos pelo homem são o dióxido de carbono (ou gás carbônico, CO2) e o metano (CH4). Esses e outros gases atuam obstruindo a dissipação do calor terrestre para o espaço. O aumento de temperatura vem ocorrendo desde meados do século XIX e deverá continuar enquanto as emissões continuarem elevadas. O aumento nas temperaturas globais e a nova composição da atmosfera desencadeiam alterações importantes em virtualmente todos os sistemas e ciclos naturais da Terra. Afetam os mares, provocando a elevação do seu nível e mudanças nas correntes marinhas e na composição química da água, verificando-se acidificação, dessalinização e desoxigenação. Interferem no ritmo das estações e nos ciclos da água, do carbono, do nitrogênio e outros compostos. Causam o degelo das calotas polares, do solo congelado das regiões frias (permafrost) e dos glaciares de montanha, modificando ecossistemas e reduzindo a disponibilidade de água potável. Tornam irregulares o regime de chuvas e o padrão dos ventos, produzem uma tendência à desertificação das regiões florestadas tropicais, enchentes e secas mais graves e frequentes, e tendem a aumentar a frequência e a intensidad"}
|
| 10 |
+
{"texto": "Abel (Ursinho Pooh) — personagem das histórias do Ursinho Pooh muitas vezes chamado apenas de Coelho"}
|
| 11 |
+
{"texto": ""}
|
| 12 |
+
{"texto": "Públio Élio Adriano (; 24 de janeiro de 76 — 10 de julho de 138), também designado como Hadriano, foi imperador romano de 117 a 138. Pertence à dinastia dos Antoninos, sendo considerado um dos \"cinco bons imperadores\". Nasceu provavelmente em Itálica, na Hispânia. Seu pai pertencia à Ordem Senatorial e era primo do imperador Trajano. Quando este faleceu, a imperatriz-viúva, Pompeia Plotina, alegou que em seu leito de morte seu marido havia adotado Adriano e o nomeado sucessor. É incerto se isso realmente ocorreu, mas o Senado e o Exército aprovaram a escolha. Porém, pouco depois quatro importantes senadores que haviam se oposto foram acusados de conspiração pelo prefeito pretoriano Públio Acílio Aciano e condenados à morte ilegalmente. O Senado o responsabilizou pelo crime e nunca o perdoou. Fez outros opositores ao abandonar a política expansionista de seu antecessor e alguns territórios recentemente conquistados, como a Assíria, a Mesopotâmia, a Armênia e partes da Dácia, preferindo investir na consolidação das fronteiras e na unificação dos diversos povos que viviam no Império. Foi um imperador viajante, visitando quase todas as províncias e passando muito tempo longe de Roma. Encorajou a disciplina e a prontidão no Exército e promoveu, projetou ou financiou pessoalmente várias instituições e edifícios civis e religiosos. Em Roma reconstruiu o Panteão e construiu o grande Templo de Vênus e Roma. Era um amante da cultura grega e procurou fazer de Atenas a capital cultural do Império, ordenando a construção de vários templos suntuosos na cidade. Suprimiu a Revolta de Barcoquebas na Judeia, que entendeu como o sinal do fracasso de seus planos de estabelecer um ideal pan-helênico, mas fora este evento, seu reinado foi em geral pacífico. Em seus últimos anos foi aflito po"}
|
| 13 |
+
{"texto": "Alberto da Prússia (1837-1906) — marechal-general de campo do exercito prussiano e regente do Ducado de Brunsvique Alberto Vitor, Duque de Clarence e Avondale — filho mais velho de Eduardo VII do Reino Unido"}
|
| 14 |
+
{"texto": "Alexandre é um prenome popular da língua portuguesa. É cognato ao nome Alexander, da língua inglesa. Em países lusófonos, pessoas chamadas Alexandre são normalmente apelidadas de Alex. O primeiro registro conhecido do nome foi feito no grego micênico: encontrou-se a versão feminina do nome, Alexandra, escrito em Linear B. Albanês – Aleksandër, Aleks, Leka i Madh, Lekë (no norte da Albânia), Sandër, Skëndër, Skander (ver Skanderbeg) Georgiano – ალექსანდრე (Alexandre), ალეკო (Aleko), ლექსო (Lekso), სანდრო (Sandro) Alexandre da Rússia - cognome de vários imperadores da Rússia (Alexandre I da Rússia, Alexandre II da Rússia, Alexandre III da Rússia) Alexandre da Escócia - cognome de vários reis da Escócia (Alexandre I da Escócia, Alexandre II da Escócia, Alexandre III da Escócia)"}
|
| 15 |
+
{"texto": "Allen - Timothy Field Allen 1837-1902: médico homeópata, ficólogo, e botânico estadounidense (nos vegetais) Allen - Joel Asaph Allen 1838-1921: zoólogo e ornitólogo estadounidense (nos animais)"}
|
| 16 |
+
{"texto": ""}
|
| 17 |
+
{"texto": "Afonso de Portugal (Lisboa, 18 de maio de 1475 — Almeirim, 13 de Julho de 1491) era o único filho e herdeiro de e de D. Leonor, reis de Portugal. O rei tanto adorava este seu filho que, em sua homenagem, batizou de \"Príncipe\" a menor ilha do arquipélago de São Tomé e Príncipe. Ainda criança, D. Afonso casou com a princesa Isabel de Aragão, filha mais velha dos Reis Católicos. e tinham um herdeiro, João, que era um jovem frágil e que viria a falecer com dezanove anos de idade. A princesa Isabel seria, portanto, a herdeira mais provável das coroas de Castela e Aragão e, como estava casada com o príncipe herdeiro de Portugal, adivinhava-se uma união dos reinos ibéricos sob a alçada de Portugal. Afonso morreu de uma queda de cavalo durante um passeio, em Alfange, Santarém, à beira do Tejo. Segundo Bernardo Rodrigues, em os Anais de Arzila, o seu aio era João de Meneses, conde de Cantanhede, e esse acontecimento terá ocasionado nesta personagem um grande traumatismo: Depois da morte de D. Afonso, nomeou como sucessor o Duque de Beja, seu primo, que viria a governar como e que casou depois com Isabel, a viúva do infante Afonso."}
|
| 18 |
+
{"texto": "A Ideia Perigosa de Darwin (em Portugal) ou A Perigosa Ideia de Darwin (no Brasil), Darwin's Dangerous Idea no original em inglês, é um livro da autoria de Daniel C. Dennett (1995) que explora os efeitos que a teoria da evolução de Charles Darwin terá produzido no pensamento filosófico ocidental. Segundo o autor, a teoria de Darwin sugere que a vida no planeta Terra foi produzida por um processo algorítmico absolutamente cego, enquanto pensadores da época de Darwin defendiam que só Deus poderia criar todas as coisas concebidas. Através da seleção natural, a concepção e a própria noção de Deus seriam criadas a partir de coisas mais simples. Através da biologia, Darwin teria encontrado uma solução para um problema de filosofia antiga: as origens da concepção. Dennett introduz termos como \"gruas\" (mecanismos que produzem concepção de baixo para cima sem a necessidade de uma entidade superior) e \"Ganchos Celestes\" (mecanismos que criam concepção por meios milagrosos), colocando-os com um papel preponderante de entre os possíveis mecanismos susceptíveis de criar concepção. Defende também a ideia de que Darwin conseguiu encontrar um processo de concepção que dispensa a existência de uma inteligência superior, baseado na ideia de seleção natural. Um dos temas discutidos no livro é o adaptacionismo. O autor procura mostrar que os tímpanos de Stephen Jay Gould na realidade não existem e são de facto exaptações. Dennett concede que Stephen Jay Gould chamou a atenção para alguns problemas importantes como o pan-adaptacionismo, mas defende que os darwinistas clássicos nunca foram adaptacionistas e que sempre tomaram em consideração outros factores. Dennett mostra que Stephen Jay Gould não refutou o adaptacionismo. Pelo contrário, deu-lhe mais consistência. Fundamentalismo darwinian"}
|
| 19 |
+
{"texto": "Agricultura é a prática de cultivar plantas e criar gado. Foi o principal desenvolvimento na ascensão da civilização humana sedentária, por meio da qual o uso de espécies domesticadas criou excedentes de alimentos que permitiram às pessoas viver nas cidades. A história da agricultura começou há milhares de anos. Depois de coletar grãos silvestres por pelo menos 105 mil anos, os primeiros agricultores começaram a plantá-los há cerca de 11,5 mil anos. Animais como porcos, ovelhas e bois foram domesticados há mais de 10 mil anos. As plantas foram cultivadas independentemente em pelo menos onze regiões do mundo. Desde o século XX, no entanto, a agricultura industrial baseada na monocultura em grande escala passou a dominar a produção agrícola, embora cerca de 2 bilhões de pessoas ainda dependiam da agricultura de subsistência. Os principais produtos agrícolas podem ser agrupados em alimentos, fibras, combustíveis e matérias-primas (como a borracha). As classes de alimentos incluem cereais (grãos), vegetais, frutas, óleos, carnes, leite, ovos e fungos. Mais de um terço dos trabalhadores do mundo estão empregados na agricultura, perdendo apenas para o setor de serviços, embora nas últimas décadas a tendência global de diminuição do número de trabalhadores agrícolas continue, especialmente nos países em desenvolvimento onde a pequena propriedade está sendo superada pela agricultura industrial e pela mecanização, o que traz um enorme aumento no rendimento das culturas agrícolas. A agronomia moderna, o melhoramento de plantas, os agroquímicos, como pesticidas e fertilizantes, e os desenvolvimentos tecnológicos aumentaram drasticamente o rendimento das culturas, mas causaram vastos danos ecológicos e ambientais. A criação seletiva e as práticas modernas na pecuária também aumenta"}
|
| 20 |
+
{"texto": "O Afeganistão (em e ), oficialmente Emirado Islâmico do Afeganistão (; ), é um país sem litoral, montanhoso, localizado no centro da Ásia, estando na encruzilhada entre o Sul da Ásia, a Ásia Central e a Ásia Ocidental. Faz fronteira com o Paquistão ao sul e ao leste, com o Irã ao oeste, com o Turcomenistão, Uzbequistão e Tajiquistão ao norte e com China no nordeste. Ocupando , sendo o 41.º maior do mundo em área, o Afeganistão é predominantemente montanhoso, com planícies no norte e sudoeste. Cabul é a capital e a maior cidade, com uma população estimada em 4,6 milhões, sendo o 37.º país mais populoso do mundo, composta principalmente de etnias pastós, tajiques, hazaras e usbeques. O território do Afeganistão foi um ponto essencial para a rota da seda e para a migração humana. Arqueólogos encontraram evidências de presença humana remontantes ao Paleolítico Médio (). A civilização urbana pode ter começado entre e O país fica em uma localização geoestratégica importante que liga o Oriente Médio à Ásia Central e ao subcontinente indiano, tendo sido a casa de vários povos através dos tempos. A terra tem testemunhado muitas campanhas militares, desde a Antiguidade: as mais notáveis feitas por Alexandre o Grande, Chandragupta Máuria, Gêngis Cã, pela União Soviética e, mais recentemente, pelos Estados Unidos e OTAN. Também foi local de origem de várias dinastias locais como os Greco-bactrianos, Cuchanas, Safáridas, Gasnévidas, Gúridas, Timúridas, Mogóis e muitos outros que criaram seus próprios impérios. A história política moderna do Afeganistão começa em 1709, com a ascensão dos pastós, quando a dinastia Hotaki foi criada em Candaar, seguida por Ahmad Shah Durrani, subindo ao poder em 1747. A capital do Afeganistão foi transferida em 1776 de Candaar para Cabul e parte do "}
|
| 21 |
+
{"texto": "A história do Afeganistão é marcada pela miscigenação e pelo confluir da influência de diversos povos e civilizações asiáticas, devido à sua posição geográfica estratégica, numa zona de transição, de altos conflitos geopolíticos e de movimentos migratórios. Por estar entre a Índia, a China, o Oriente Médio e a Europa Oriental, o Afeganistão tem uma grande importância como rota comercial, tendo servido historicamente como zona central da Rota de Seda. O Afeganistão como Estado surge em 1823 como \"Emirado do Afeganistão\", sendo controlado pelo Império Durrani. A criação desse Emirado ocorreu com a unificação de diversas tribos, como os pastós, tajiques, hazaras, usbeques e turcomenos, unificando-os como afegãos. Os primeiros registros escritos da terra do atual Afeganistão datam de aproximadamente 500 A.P, quando a área era controlada pelo Império Aquemênida. Outras evidências apontam para a existência de culturas urbanas avançadas entre 3000 e 2000 A.P. Alexandre o Grande e o Império Macedônico chegaram no que hoje é o Afeganistão por volta de 330 A.P, após a queda do Império Aquemênida durante a Batalha de Gaugamela. Após isso, inúmeros impérios e Estados se estabeleceram na região, incluindo o reino Greco-Báctrio, o Império Cuchana, o Império Sassânida, o Império Gúrida, a Dinastia Timúrida, o Império Hotaqui, o Império Durrani e muitas outras sociedades persianizadas. Podemos considerar que o primeiro gérmen nacionalista afegão nasceu durante este período, com a reforma religiosa de Zoroastro (), que originou um reino monárquico organizado de tribos arianas. Em , a região é conquistada por Alexandre da Macedónia que aí estabeleceu várias cidades designadas por Alexandria. Essas cidades terão dado origem, provavelmente, a Candaar e a Cabul. A primeira Alexandria aí fun"}
|
| 22 |
+
{"texto": "Argentina, oficialmente República Argentina (), é o segundo maior país da América do Sul em território e o terceiro em termos de população, constituída como uma federação de 23 províncias e uma cidade autônoma, Buenos Aires, capital do país. É o oitavo maior país do mundo em área territorial e o maior entre as nações de língua espanhola, embora México, Colômbia e Espanha, que possuem menor território, sejam mais populosos. A área continental da Argentina está entre a cordilheira dos Andes a oeste e o oceano Atlântico, a leste. Faz fronteira com o Paraguai e Bolívia ao norte, com o Brasil e Uruguai a nordeste e com o Chile a oeste e sul. A Argentina reivindica uma parte da Antártida, sobrepondo as reivindicações do Chile e do Reino Unido no continente antártico, mesmo após todas as reivindicações terem sido suspensas pelo Tratado da Antártida de 1961. O país reivindica ainda as Ilhas Malvinas () e Geórgia do Sul e Sandwich do Sul, que são administradas pelo Reino Unido como territórios britânicos ultramarinos. O mais antigo registro de presença humana na área atualmente conhecida como Argentina é datado do período paleolítico. A colonização espanhola iniciou-se em 1512. A Argentina emergiu como o Estado sucessor do Vice-Reino do Rio da Prata, uma colônia espanhola fundada em 1776. A declaração e a luta pela independência (1810–1818) foi seguida por uma longa guerra civil, que durou até 1861 e terminou com a reorganização do país em uma federação de províncias, com a cidade de Buenos Aires como capital. Durante a segunda metade do século XX, a Argentina enfrentou vários golpes militares e períodos de instabilidade política, juntamente com crises econômicas periódicas que contiveram seu pleno desenvolvimento econômico e social. Uma potência média reconhecida, a Argentina é"}
|
| 23 |
+
{"texto": "Em matemática e ciência da computação, um algoritmo é uma sequência finita de ações executáveis que visam obter uma solução para um determinado tipo de problema. Segundo Dasgupta, Papadimitriou e Vazirani; \"Algoritmos são procedimentos precisos, não ambíguos, padronizados, eficientes e corretos.\". As suas características são: finitas, o algoritmo deve eventualmente resolver o problema; bem definidas: os passos devem ser definidos de modo a serem entendidos; efetivas, deve sempre resolver o que tem para solucionar, antecipando falhas. O conceito de algoritmo existe há séculos e o uso do conceito pode ser atribuído a matemáticos russos, por exemplo a Peneira de Eratóstenes e o algoritmo de Euclides. O conceito de algoritmo é frequentemente ilustrado pelo exemplo de uma receita culinária, embora muitos algoritmos sejam mais complexos. Eles podem repetir passos (fazer iterações) ou necessitar de decisões (tais como comparações ou lógica) até que a tarefa seja completada. Um algoritmo corretamente executado não irá resolver um problema se estiver implementado incorretamente ou se não for apropriado ao problema. Um algoritmo não representa, necessariamente, um programa de computador, e sim os passos necessários para realizar uma tarefa. Sua implementação pode ser feita por um computador, por outro tipo de autômato ou mesmo por um ser humano. Diferentes algoritmos podem realizar a mesma tarefa usando um conjunto diferenciado de instruções em mais ou menos tempo, espaço ou esforço do que outros. Tal diferença pode ser reflexo da complexidade computacional aplicada, que depende de estruturas de dados adequadas ao algoritmo. Por exemplo, um algoritmo para se vestir pode especificar que você vista primeiro as meias e os sapatos antes de vestir a calça enquanto outro algoritmo espe"}
|
| 24 |
+
{"texto": "O (Ananas comosus) é uma infrutescência tropical produzida pela planta de mesmo nome, caracterizada como uma planta monocotiledônea da família das bromeliáceas da subfamília Bromelioideae. É um símbolo das regiões tropicais e subtropicais. Os abacaxizeiros cultivados pertencem à espécie Ananas comosus, que compreende muitas variedades frutíferas. Há também várias espécies selvagens, pertencentes ao mesmo gênero. O fruto, quando maduro, suas folhas se soltam facilmente ao puxar, tem o sabor bastante ácido e, muitas vezes, adocicado. De acordo com o escritor e linguista Clóvis Chiaradia, o termo \"abacaxi\" (em português brasileiro) apresenta duas possíveis etimologias, ambas provenientes da família Tupi-Guarani, elas são: a) da junção dos termos \"I'bá\" (fruto) e \"cati\" ou \"caxi\" (cheiroso), ou seja, \"fruto de recende\"; b) da junção dos termos \"I'bá\" (fruto), \"caá\" (folha) e \"ti\" ou \"xi\" (fruto de ponta aguda). O termo \"ananás\" (em português europeu e espanhol) é do guarani e tupi antigo naná, e documentado em português na primeira metade do séc. XVI e em espanhol na segunda (1578), sendo empréstimo do português do Brasil ou da sua língua geral. O abacaxi é um fruto-símbolo de regiões tropicais e subtropicais, de grande aceitação em todo o mundo, quer ao natural, quer industrializado: agrada aos olhos, ao paladar e ao olfato. Por essas razões e por ter uma \"coroa\", cabe-lhe, por vezes, o cognome de \"rei dos frutos\", que lhe foi dado, logo após seu descobrimento, pelos portugueses. Na linguagem corrente do Brasil, tal como em Angola, costuma-se designar por \"ananás\" os frutos de plantas não cultivadas, de variedades menos conhecidas ou de qualidade inferior. Por sua vez, a palavra \"abacaxi\" costuma ser empregada não apenas para designar o fruto de melhor qualidade, mas a p"}
|
| 25 |
+
{"texto": "Angola, oficialmente República de Angola, é um país da costa ocidental de África, cujo território principal é limitado a norte e a nordeste pela República Democrática do Congo, a leste pela Zâmbia, a sul pela Namíbia e a oeste pelo Oceano Atlântico. Inclui também o exclave de Cabinda, através do qual faz fronteira com a República do Congo, a norte. Para além dos vizinhos já mencionados, Angola é o país mais próximo da colónia britânica de Santa Helena. Os portugueses estiveram presentes desde o em alguns pontos do que é hoje o território de Angola, interagindo de diversas maneiras com os povos nativos, principalmente com os habitantes do litoral. A delimitação do território apenas aconteceu no início do . O primeiro europeu a chegar a Angola foi o explorador português Diogo Cão. Angola foi uma colónia portuguesa que apenas abrangeu o actual território do país no e a \"ocupação efectiva\", como determinado pela Conferência de Berlim em 1884, aconteceu apenas na década de 1920. A independência do domínio português foi alcançada em 1975, depois de uma guerra de independência. O Brasil foi o primeiro país a reconhecer a independência do país, ainda em 1975. Após a independência, Angola foi palco de uma longa e devastadora guerra civil, de 1975 a 2002, sobretudo entre o MPLA e a UNITA. Apesar do conflito interno, áreas como a Baixa de Cassanje mantiveram activos seus sistemas monárquicos regionais. No ano de 2000 foi assinado um acordo de paz com a Frente para a Libertação do Enclave de Cabinda, organização de guerrilha que luta pela secessão de Cabinda e que ainda se encontra activa. É da região de Cabinda que sai aproximadamente 65% do petróleo de Angola. O país tem vastos recursos naturais, como grande reservas de minerais e de petróleo e, desde 1990, sua economia tem apr"}
|
| 26 |
+
{"texto": "Aves são uma classe de seres vivos vertebrados endotérmicos caracterizada pela presença de penas, um bico sem dentes, oviparidade de casca rígida, elevado metabolismo, um coração com quatro câmaras e um esqueleto pneumático resistente e leve. As aves estão presentes em todas as regiões do mundo e variam significativamente de tamanho, desde os 5 cm do colibri até aos 2,75 m da avestruz. São a classe de tetrápodes com o maior número de espécies vivas, aproximadamente dez mil, das quais mais de metade são passeriformes. As aves apresentam asas, que são mais ou menos desenvolvidas dependendo da espécie. Os únicos grupos conhecidos sem asas são as moas e as aves-elefante, ambos extintos. As asas, que evoluíram a partir dos membros anteriores, oferecem às aves a capacidade de voar, embora a especiação tenha produzido aves não voadoras, como as avestruzes, pinguins e diversas aves endémicas insulares. Os sistemas digestivo e respiratório das aves estão adaptados ao voo. Algumas espécies de aves que habitam em ecossistemas aquáticos, como os pinguins e a família dos patos, desenvolveram a capacidade de nadar. Algumas aves, especialmente os corvos e os papagaios, estão entre os animais mais inteligentes do planeta. Algumas espécies constroem e usam ferramentas e passam o conhecimento entre gerações. Muitas espécies realizam migrações ao longo de grandes distâncias. A maioria das aves são animais sociais que comunicam entre si com sinais visuais, chamamentos e cantos, e realizam atividades comunitárias como procriação e caça cooperativa, voo em bando e grupos de defesa contra predadores. A grande maioria das espécies de aves são monogâmicas, geralmente durante uma época de acasalamento e por vezes durante vários anos, mas raramente durante toda a vida. Outras espécies são polígam"}
|
| 27 |
+
{"texto": ""}
|
docs/memorias/r-34-analise-provas-qwen-v090.md
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# r-34 — Análise, Provas e Testes das Críticas de Arquitetura do Agente Qwen3.8 (v0.9.0)
|
| 2 |
+
|
| 3 |
+
**Escopo**: o usuário pediu *analisar, provar e testar* o segundo lote de
|
| 4 |
+
críticas do agente Qwen3.8 (engenharia de software Rust e design de ML),
|
| 5 |
+
mantendo o princípio da casa: **nenhuma funcionalidade SOTA eficaz é
|
| 6 |
+
removida**; toda mudança com prova matemática, lógica e de lógica
|
| 7 |
+
computacional; provas em markdown; medições honestas; autocrítica.
|
| 8 |
+
|
| 9 |
+
**Metodologia**: (i) verificação simbólica/lógica de cada crítica e de cada
|
| 10 |
+
proposta ANTES de qualquer código; (ii) confronto com oráculos independentes
|
| 11 |
+
(referências v0.8.0 preservadas, fonte do candle 0.11, medições frias);
|
| 12 |
+
(iii) implementação apenas do que sobrevive a (i)+(ii), como **adição**
|
| 13 |
+
(métodos antigos viram oráculos `pub(crate)`, nunca lixo); (iv) testes de
|
| 14 |
+
regressão + determinismo 3×; (v) benchmark com aquecimento e mediana de 3.
|
| 15 |
+
|
| 16 |
+
**Veredito sumário**:
|
| 17 |
+
|
| 18 |
+
| # | Crítica | Veredito | Ação v0.9.0 | Ganho medido |
|
| 19 |
+
|---|---------|----------|-------------|--------------|
|
| 20 |
+
| 1 | God Object (lib.rs 105 kB) + acoplamento testes/bindings | **VÁLIDA no essencial, IMPRECISA em detalhes** | FFI extraída para `src/python.rs` atrás de `feature = "python"`; `treino.rs` desacoplado do pyo3 | domínio testa SEM Python: 107/107; overhead Python medido 17,6% (não "≈40%") |
|
| 21 |
+
| 2a | `skew` aloca seleção densa S ∈ R^{m×n²} (Θ(n⁴)) | **VÁLIDA** — mas a proposta quebraria o autograd | `index_add` rastreada: Θ(n²) diferenciável, bit-a-bit | 3,8× (n=16) / 98× (n=64) / **919× (n=128)**; memória **2335×** menor; n=256 viável (antes: 8,6 GB só p/ S) |
|
| 22 |
+
| 2b | `fwd` quebra o gradiente e segue na API pública | **VÁLIDA** (bug v080-1 já catalogado em r-33 §5) | `fwd` → `pub(crate)` + `#[deprecated]` (oráculo dos testes M-R6/M-R7); `fwd_vetorizado` → **`forward`** canônico | API pública 100% íntegra em gradiente; valores idênticos (dif = 0,0); +3 sítios remanescentes migrados |
|
| 23 |
+
| 2c | `calibrar` em laços CPU ("use kernels SIMD do candle") | **PREMISSA FALSA na CPU** — o kernel `max(0)` do candle é mais lento | laço **zero-cópia** no storage (elimina a materialização REAL) + `calibrar_tensor` opt-in (GPU) | **1,56×** mais rápido, bit-a-bit; variante tensor 15–18× MAIS LENTA na CPU (análise do kernel) |
|
| 24 |
+
| 3 | "provas em comentários" → sistema de tipos | **PARCIALMENTE VÁLIDA** — mas a proposta `pub struct P(pub f64)` não prova NADA | newtypes `Probabilidade`/`GateAtivacao` com campo PRIVADO + construtor validado (T-V1/T-V2) | fronteira de domínio verificada em compilação; Kani = débito justificado |
|
| 25 |
+
| — | Nomenclatura PT/EN misturada | **REJEITADA a renomeação em massa** | convenção documentada (API pública PT-BR por design; `forward` como exceção padrão de ML) | 0 quebras nos 30+ scripts existentes |
|
| 26 |
+
|
| 27 |
+
---
|
| 28 |
+
|
| 29 |
+
## §2 — Crítica 1 + Aprimoramento 4: o "God Object" e o split da FFI
|
| 30 |
+
|
| 31 |
+
### 2.1 Análise da crítica
|
| 32 |
+
|
| 33 |
+
**Válido**: `lib.rs` tinha **104.558 bytes** com 42 `#[pyfunction]`, 5
|
| 34 |
+
`#[pyclass]`, o `#[pymodule]` inteiro e toda a cola Python
|
| 35 |
+
(`carregar_tokenizador`, `tensor_de_2d`, `py_err`, `callback`) — violação
|
| 36 |
+
real de SRP/SoP: lógica de domínio e FFI no mesmo arquivo; compilação
|
| 37 |
+
incremental lenta (qualquer toque na FFI recompila a fachada inteira).
|
| 38 |
+
|
| 39 |
+
**Impreciso na crítica**: (a) lib.rs **não continha** `#[cfg(test)]` — os
|
| 40 |
+
testes de invariantes já viviam inline nos módulos de domínio (verificado:
|
| 41 |
+
`grep '#\[cfg(test)\]' lib.rs` = 0 ocorrências); a mistura
|
| 42 |
+
"ta7_equivalencia_bit_a_bit com demo_qwen_v080" era entre ARQUIVOS
|
| 43 |
+
(testes no módulo, demos na FFI), não dentro do lib.rs; (b) a "Prova
|
| 44 |
+
Lógica" do Qwen afirma que o compilador "analisa dependências a nível de
|
| 45 |
+
crate e módulo" — impreciso: o cargo recompila por *crate* com granularidade
|
| 46 |
+
de *feature*; o ganho real e mensurável é **não compilar nem linkar** a
|
| 47 |
+
família pyo3 quando a feature `python` está desligada (§2.3).
|
| 48 |
+
|
| 49 |
+
### 2.2 Prova lógica (A-1: separação de dependências) ∎
|
| 50 |
+
|
| 51 |
+
**Enunciado**: com a FFI isolada em `#[cfg(feature = "python")] pub mod
|
| 52 |
+
python` e as dependências pyo3 marcadas `optional = true`, a suíte de
|
| 53 |
+
testes de domínio compila e executa sem que o crate pyo3 (nem numpy-python,
|
| 54 |
+
pyo3-log, pyo3-async-runtimes, tokio) seja sequer baixado-compilado.
|
| 55 |
+
|
| 56 |
+
**Prova**: a dependência sintática de `khtst-rust` (lib) para pyo3 existe
|
| 57 |
+
unicamente através de (i) `src/python.rs` e (ii) `src/treino.rs`
|
| 58 |
+
(`CallbackPy`). (i) é eliminável por `#[cfg]` (o item some da árvore de
|
| 59 |
+
módulos quando a feature está desligada); (ii) é eliminável por
|
| 60 |
+
re-tipagem: `CallbackPy = Option<Py<PyAny>>` foi substituído pelo tipo de
|
| 61 |
+
domínio `CallbackTreino = Option<Arc<dyn Fn(&serde_json::Value) + Send +
|
| 62 |
+
Sync>>` — `Py<PyAny>` é `Send + Sync`, logo o callable Python é
|
| 63 |
+
embrulhável num closure desse tipo NA FFI (adaptador
|
| 64 |
+
`callback_treino_de_py`), sem que o tipo de domínio mencione pyo3. Com (i)+(ii),
|
| 65 |
+
o grafo de `use` de todo módulo de domínio é livre de pyo3; como o rustc
|
| 66 |
+
só compila crates presentes no grafo de dependências resolvido pelas
|
| 67 |
+
features ativas, `cargo test --no-default-features` compila
|
| 68 |
+
khtst-rust+candle sem pyo3. ∎ **Verificação executável**: `cargo test
|
| 69 |
+
--no-default-features` → 105+2 = **107/107 verdes** (3 execuções
|
| 70 |
+
idênticas); a suíte de integração `tests/provas.rs` (G5–G20) incluída.
|
| 71 |
+
|
| 72 |
+
### 2.3 Medição honesta (corrige a alegação "≈40%")
|
| 73 |
+
|
| 74 |
+
Builds frios (target dirs separados, mesma máquina, perfil dev):
|
| 75 |
+
|
| 76 |
+
| Configuração | tempo |
|
| 77 |
+
|---|---|
|
| 78 |
+
| `cargo test --no-default-features --no-run` (domínio) | **70 s** |
|
| 79 |
+
| `cargo test --no-run` (python + ponte_async) | **85 s** |
|
| 80 |
+
|
| 81 |
+
O overhead da FFI nesta máquina é **17,6%** (15 s), não "≈40%". A
|
| 82 |
+
alegação do Qwen não é teorema — depende do grafo de crates e da máquina;
|
| 83 |
+
a nossa é a medida local, com candle-core compilado igualmente nos dois
|
| 84 |
+
cenários (diferença isolada à família pyo3). O ganho estrutural além do
|
| 85 |
+
tempo: `lib.rs` 104.558 B → **1.250 B** (razão 83,6×); a FFI inteira
|
| 86 |
+
(112.410 B) agora é uma unidade coerede editável isoladamente.
|
| 87 |
+
|
| 88 |
+
### 2.4 Limpeza conexas (deps mortas)
|
| 89 |
+
|
| 90 |
+
`numpy 0.23`, `dict_derive 0.5` e `pyo3-built 0.5` tinham **zero usos** no
|
| 91 |
+
fonte (verificado por busca exaustiva) — removidas do Cargo.toml. Menos
|
| 92 |
+
superfície de compilação e de auditoria de segurança. `built` (build-dep)
|
| 93 |
+
permanece (usado por build.rs).
|
| 94 |
+
|
| 95 |
+
---
|
| 96 |
+
|
| 97 |
+
## §3 — Crítica 2a + Aprimoramento 1: `skew` em Θ(n⁴) → Θ(n²)
|
| 98 |
+
|
| 99 |
+
### 3.1 Análise da crítica e ERRATA da proposta
|
| 100 |
+
|
| 101 |
+
**A crítica é matematicamente correta**: a v0.8.0 construía U(θ) por
|
| 102 |
+
`θ(1,m) @ S(m,n²)` com S densa de seleção — espaço e tempo Θ(m·n²) = Θ(n⁴)
|
| 103 |
+
(n=128: 508 MiB só para S; n=256: **8,6 GB**, inviável).
|
| 104 |
+
|
| 105 |
+
**A proposta do Qwen é inviável como está**: `th.to_vec1::<f32>()` +
|
| 106 |
+
laço + `Tensor::from_vec` **secciona o grafo de autograd** — `to_vec1`
|
| 107 |
+
lê os valores e `from_vec` cria um tensor-FOLHA desconectado; o gradiente
|
| 108 |
+
∂L/∂θ ficaria **exatamente 0**. É a mesma classe do bug v080-1 (r-33 §5),
|
| 109 |
+
agora proposta justamente no módulo onde a v0.8.0 tinha resolvido isso com
|
| 110 |
+
a matriz de seleção (o comentário do código avisava: "construção
|
| 111 |
+
DIFERENCIÁVEL... sem slice_assign"). Trocar Θ(n⁴) diferenciável por Θ(n²)
|
| 112 |
+
não-diferenciável é remover a funcionalidade SOTA (aprendizado das
|
| 113 |
+
rotações) — vedado pela regra da casa.
|
| 114 |
+
|
| 115 |
+
**A correção**: `index_add` sobre um vetor de zeros — operação RASTREADA
|
| 116 |
+
(`BackpropOp::IndexAdd` no fonte do candle, op.rs:87), disponível para
|
| 117 |
+
tensores 1-D com índices U32 no backend CPU (mod.rs:2945).
|
| 118 |
+
|
| 119 |
+
### 3.2 Teo F-13 (equivalência bit-a-bit com a v0.8.0) ∎
|
| 120 |
+
|
| 121 |
+
**Enunciado**: seja `A_novo` o skew construído por
|
| 122 |
+
`zeros(n²).index_add(sup, θ).index_add(inf, −θ)` e `A_ref` o da v0.8.0
|
| 123 |
+
(`θ(1,m) @ S` seguido de `U − Uᵀ`). Para todo θ finito (após clamp),
|
| 124 |
+
`A_novo = A_ref` **bit-a-bit**.
|
| 125 |
+
|
| 126 |
+
**Prova**: na referência, cada posição p do produto tem exatamente um
|
| 127 |
+
termo não-nulo: `U_p = Σ_k θ_k·S[k,p] = θ_{k(p)} + (m−1)·(±0,0)`; em
|
| 128 |
+
IEEE-754 com arredondamento ao mais próximo, `x + (±0,0) = x` para todo x
|
| 129 |
+
finito (e o caso x = −0,0: `(−0,0)+(+0,0) = +0,0`, idem no index_add:
|
| 130 |
+
`(+0,0)+(−0,0) = +0,0` — mesma saída), qualquer que seja a ordem de soma
|
| 131 |
+
do gemm. No novo, `A_p = 0,0 + θ_{k(p)} = θ_{k(p)}` (index_add CPU:
|
| 132 |
+
`dst[i] += src[j]`). Logo `U = A_novo,sup` bit-a-bit; `−θ` por `affine(−1,0)`
|
| 133 |
+
é exato (negar o bit de sinal); `A = U − Uᵀ` é a MESMA operação nas duas
|
| 134 |
+
versões; a distribuição dos pares (i,j) na ordem lexicográfica é idêntica
|
| 135 |
+
à da construção de S. ∎ **Teste f13**: n ∈ {2,4,8,16,17}, θ ∈ [−1,4, 1,4]
|
| 136 |
+
(exercita clamp e espelho), `to_bits()` idêntico em todas as entradas e
|
| 137 |
+
`A + Aᵀ = 0` exato.
|
| 138 |
+
|
| 139 |
+
### 3.3 Teo F-14 (custo e gradiente) ∎
|
| 140 |
+
|
| 141 |
+
1. **Espaço**: novo aloca `n²` f32 (zeros) + `2m` u32 (índices) + `m` f32
|
| 142 |
+
(−θ) = Θ(n²) bytes, contra Θ(m·n²) = Θ(n⁴) da referência. n=256:
|
| 143 |
+
256 KiB + 384 KiB contra **8,6 GB** — a referência é inviável em RAM
|
| 144 |
+
comum; o novo executa (teste f14 constrói A(256) sem esforço).
|
| 145 |
+
2. **Tempo**: o custo dominante da referência é o gemm (1,m)×(m,n²):
|
| 146 |
+
Θ(n⁴) FLOPs + o preenchimento de S (Θ(n⁴) escritas). O novo custa
|
| 147 |
+
Θ(m) adições + Θ(n²) zero-fill. Medição (§3.4) confirma a razão
|
| 148 |
+
assintótica crescendo com n.
|
| 149 |
+
3. **Gradiente preservado**: `index_add`, `affine`, `reshape` são
|
| 150 |
+
rastreadas ⇒ ∂L/∂θ ≠ 0 (teste f14 com θ≠0; e no nascimento θ=0 a perda
|
| 151 |
+
LINEAR em entrada única R[0,1] dá dR[0,1]/dθ₀ = 1 — grafo vivo). ∎
|
| 152 |
+
|
| 153 |
+
*Nota honesta (registrada nos comentários do teste)*: com L = ‖R‖²_F e
|
| 154 |
+
θ = 0, o gradiente é nulo **por matemática** (R = I ⇒ L = n + ‖A‖²_F,
|
| 155 |
+
mínimo; A skew tem traço nulo) — a primeira versão do teste f14 usava
|
| 156 |
+
essa perda e "falhava" corretamente; o teste foi reformulado com perda
|
| 157 |
+
que exercita o gradiente. Erro meu, catalogado no §9.
|
| 158 |
+
|
| 159 |
+
### 3.4 Medição (release, mediana de 3 execuç��es da demo; 5 reps cada)
|
| 160 |
+
|
| 161 |
+
| n | tempo ref (v0.8.0) | tempo novo | speedup | memória S: novo | razão |
|
| 162 |
+
|---|---|---|---|---|---|
|
| 163 |
+
| 16 | 21,6 µs | 3,2 µs | 3,8× | 122.880 : 3.424 B | 36× |
|
| 164 |
+
| 64 | 3,27 ms | 37 µs | 98× | 33,0 MB : 56,7 KB | 583× |
|
| 165 |
+
| 128 | 89,1 ms | 101 µs | **919×** | 508 MB : 223 KB | **2.335×** |
|
| 166 |
+
|
| 167 |
+
Valores bit-a-bit idênticos em todos os n (gate `q1_skew_bits_identicos`).
|
| 168 |
+
|
| 169 |
+
---
|
| 170 |
+
|
| 171 |
+
## §4 — Crítica 2b + Aprimoramento 2: a `fwd` quebrada na API pública
|
| 172 |
+
|
| 173 |
+
### 4.1 Análise
|
| 174 |
+
|
| 175 |
+
A crítica está **correta e é mais forte do que parece**: o bug v080-1
|
| 176 |
+
(`to_vec2`/`from_vec` seccionam o autograd ⇒ ∇_roteador = ∇_especialistas
|
| 177 |
+
= 0) foi corrigido na v0.8.0 pela `fwd_vetorizado`, mas a `fwd` quebrada
|
| 178 |
+
permaneceu `pub` — um usuário que escolhesse o nome "natural" (`fwd`)
|
| 179 |
+
treinaria com gradiente nulo nos especialistas SEM nenhum erro em tempo de
|
| 180 |
+
compilação. Isso viola o Princípio da Mínima Surpresa exatamente como
|
| 181 |
+
enunciado.
|
| 182 |
+
|
| 183 |
+
### 4.2 Resolução SEM remoção (prova lógica) ∎
|
| 184 |
+
|
| 185 |
+
A proposta do Qwen — "remover `fwd` e renomear `fwd_vetorizado` para
|
| 186 |
+
`forward`" — colide com a regra da casa em UM ponto: os testes **M-R6**
|
| 187 |
+
(equivalência bit-a-bit de valores entre os dois caminhos) e **M-R7**
|
| 188 |
+
(prova executável do bug: gradientes 0/0 na fwd, > 0 na vetorizada) usam a
|
| 189 |
+
`fwd` como **oráculo**. Removê-la enfraqueceria as provas de regressão que
|
| 190 |
+
garantem que a `forward` nunca regredirá ao bug.
|
| 191 |
+
|
| 192 |
+
**Resolução adotada**: (a) `fwd_vetorizado` → **`forward`** (nome canônico
|
| 193 |
+
— convenção universal nn/PyTorch); (b) `fwd` → `pub(crate)` +
|
| 194 |
+
`#[deprecated(since = "0.9.0", note = "bug v080-1...")]` — sai da
|
| 195 |
+
superfície pública (o consumidor externo não pode mais chamá-la por
|
| 196 |
+
engano) mas permanece vinculável pelos testes internos.
|
| 197 |
+
|
| 198 |
+
**Teorema (integridade da superfície)**: todo método `pub` de
|
| 199 |
+
`MoeRedirecionavel` que produz saídas treináveis mantém o grafo de
|
| 200 |
+
autograd íntegro até roteador e especialistas. *Prova*: a única função
|
| 201 |
+
`pub` de passada é `forward` (+ `fwd_ambos_par`, migrada para `forward`
|
| 202 |
+
internamente); `fwd` é `pub(crate)`; `forward` usa apenas ops rastreadas
|
| 203 |
+
(index_add, index_select, narrow, broadcast_mul/div, softmax — M-R7). ∎
|
| 204 |
+
|
| 205 |
+
### 4.3 Auditoria conexa (3 sítios remanescentes descobertos)
|
| 206 |
+
|
| 207 |
+
A migração v0.8.0 tinha deixado 3 sítios NÃO-treino ainda na `fwd`
|
| 208 |
+
(inciados por esta análise): (1) `fwd_ambos_par` (medição de paralelismo
|
| 209 |
+
M-R3 — agora mede o caminho canônico); (2) o cálculo de `std_emb` em
|
| 210 |
+
`treinar_jepa_com_moe` (estatística — valores idênticos por M-R6); (3) a
|
| 211 |
+
demo pública `demo_moe_redirecionavel` (gates M-R1 — a demo Python da API
|
| 212 |
+
pública usava o caminho quebrado!). Todos migrados para `forward`; a
|
| 213 |
+
`demo_qwen_v080` mantém `fwd` intencionalmente (`#[allow(deprecated)]` —
|
| 214 |
+
ela MEDE o bug). Valores idênticos em todos (gate
|
| 215 |
+
`q3_forward_valores_e_gradiente`: dif = 0,0; grad roteador 1,4·10⁵ > 0;
|
| 216 |
+
grad especialistas 2,1·10⁶ > 0).
|
| 217 |
+
|
| 218 |
+
---
|
| 219 |
+
|
| 220 |
+
## §5 — Crítica 2c + Aprimoramento 3: `SuavizadorQuant::calibrar`
|
| 221 |
+
|
| 222 |
+
### 5.1 Análise da premissa — FALSA na CPU (com prova no fonte)
|
| 223 |
+
|
| 224 |
+
A crítica afirma que os laços nativos "ignoram os kernels otimizados
|
| 225 |
+
(SIMD/GPU)" e que a versão em tensor seria mais rápida. **Medição inicial
|
| 226 |
+
confirmou o contrário**: a versão pura em tensor (`abs().max(0)`) ficou
|
| 227 |
+
**11× MAIS LENTA** que a referência em laços (18,3 ms vs 1,7 ms em
|
| 228 |
+
w=(512,512), x=(4096,512)).
|
| 229 |
+
|
| 230 |
+
**Causa-raiz (fonte do candle 0.11, cpu_backend/mod.rs:162-182)**: para
|
| 231 |
+
`max(0)` numa matriz row-major (R,C), o `ReduceIndex::fold_impl` percorre
|
| 232 |
+
o ramo `reduce_dim_stride ≠ 1`: `src[src_i * reduce_dim_stride]` — saltos
|
| 233 |
+
de C·4 B (2 KB) entre leituras consecutivas; **cada acesso é um cache
|
| 234 |
+
miss** e o fold escalar não é vetorizado. A referência em laços, ao
|
| 235 |
+
contrário, varre SEQUENCIALMENTE a memória (auto-vetorizável pelo LLVM).
|
| 236 |
+
A premissa "kernels otimizados" não se verifica para reduções
|
| 237 |
+
stride≠1 na CPU do candle 0.11.
|
| 238 |
+
|
| 239 |
+
### 5.2 O que a crítica acerta: a materialização
|
| 240 |
+
|
| 241 |
+
O problema REAL do código v0.8.0 era `flatten_all().to_vec1::<f32>()` —
|
| 242 |
+
cópia de O(|w|+|x|) floats (9,4 MB por chamada no cenário medido) para a
|
| 243 |
+
RAM, + 2 laços. A correção adotada elimina a cópia **mantendo** o laço
|
| 244 |
+
rápido: acesso direto ao storage (`Tensor::storage_and_layout()` +
|
| 245 |
+
`CpuStorage::as_slice::<f32>()`, ambas API pública do candle) com varredura
|
| 246 |
+
`chunks_exact(d)` — sem divisão modular por elemento (k%d custa ~20 ciclos
|
| 247 |
+
e bloqueia auto-vetorização — segunda medição: 2,4× mais lento antes
|
| 248 |
+
desta correção).
|
| 249 |
+
|
| 250 |
+
**Teo F-15 (bit-a-bit e domínio) ∎**
|
| 251 |
+
1. **Ordem de comparações idêntica**: a referência percorre r=0..R, c=0..C
|
| 252 |
+
atualizando `wmax[c]` com `if a > wmax[c]`; a nova percorre
|
| 253 |
+
`chunks_exact(d)` — a mesma sequência linear de elementos, o mesmo
|
| 254 |
+
predicado por acumulador, na mesma ordem ⇒ mesmos resultados bit-a-bit
|
| 255 |
+
(seleção por máximo é exata, sem aritmética).
|
| 256 |
+
2. **Piso preservado**: acumuladores inicializados em 1e-5 (como a v0.8.0)
|
| 257 |
+
⇒ `max(1e-5, max_r |w|)` idêntico. A proposta Qwen NÃO tinha o piso:
|
| 258 |
+
canal nulo ⇒ `w_max = 0` ⇒ escala `0^{−(1−α)} = ∞` (regressão real,
|
| 259 |
+
capturada no teste sq1 com canais zeros).
|
| 260 |
+
3. **EMA preservada em f64**: a proposta computava `affine` em f32
|
| 261 |
+
(β·o e (1−β)·n arredondados a f32 antes da soma) — mudaria os bits a
|
| 262 |
+
cada passo; a v0.9.0 mantém a acumulação f64 com UMA conversão final,
|
| 263 |
+
idêntica à v0.8.0.
|
| 264 |
+
4. **Guard preservado**: `x.dims().last() == d_in` (senão xmax fica no piso).
|
| 265 |
+
5. **NaN (diferença documentada)**: o laço ignora NaN (predicado `>` é
|
| 266 |
+
falso); o fallback tensor propaga NaN — semântica estrita no caminho
|
| 267 |
+
acelerado. ∎
|
| 268 |
+
|
| 269 |
+
### 5.3 Medição (release, mediana de 3; w=(512,512), x=(4096,512))
|
| 270 |
+
|
| 271 |
+
| Variante | tempo | notas |
|
| 272 |
+
|---|---|---|
|
| 273 |
+
| v0.8.0 (`to_vec1` + laços) | 1,71 ms | referência (oráculo) |
|
| 274 |
+
| **v0.9.0 zero-cópia** | **1,10 ms** | **1,56×**, bits idênticos, 0 cópia |
|
| 275 |
+
| tensor pura (`calibrar_tensor`) | 16,7–21,9 ms | **opt-in GPU** (15–18× mais lenta na CPU) |
|
| 276 |
+
|
| 277 |
+
`calibrar_tensor` permanece publicada como opt-in documentada: em backends
|
| 278 |
+
acelerados (CUDA/Metal) ela evita o round-trip dos dados à CPU — onde a
|
| 279 |
+
análise do §5.1 não se aplica (a redução roda on-device). Em CPU, o
|
| 280 |
+
caminho zero-cópia domina.
|
| 281 |
+
|
| 282 |
+
---
|
| 283 |
+
|
| 284 |
+
## §6 — Crítica 3 + Aprimoramento 5: "provas" e o sistema de tipos
|
| 285 |
+
|
| 286 |
+
### 6.1 Análise e ERRATA da proposta
|
| 287 |
+
|
| 288 |
+
A crítica tem razão NO DIAGNÓSTICO (comentários não são verificados pelo
|
| 289 |
+
compilador) e está ERRADA NA SOLUÇÃO dada: `pub struct
|
| 290 |
+
Probabilidade(pub f64)` **não garante nada** — o campo público permite
|
| 291 |
+
`Probabilidade(7.0)` em qualquer expressão; o verificador de tipos aceita.
|
| 292 |
+
Transferir a prova para o tipo exige **encapsulamento**: campo privado +
|
| 293 |
+
construtor validado. (Exemplo didático da diferença entre "tipagem nominal
|
| 294 |
+
decorativa" e "tipagem com refinamento".)
|
| 295 |
+
|
| 296 |
+
A regra da casa (provas em markdown) permanece — é exigência do usuário e
|
| 297 |
+
é onde vivem as provas ESTRUTURAIS (convergência, ordem de operações,
|
| 298 |
+
complexidade). Os newtypes cobrem o subconjunto onde o sistema de tipos é
|
| 299 |
+
MAIS FORTE que comentários: invariantes de domínio escalar.
|
| 300 |
+
|
| 301 |
+
### 6.2 Teo T-V1 (soundness do newtype encapsulado) ∎
|
| 302 |
+
|
| 303 |
+
**Enunciado**: todo valor de `Probabilidade` observável fora do módulo
|
| 304 |
+
`tipos` satisfaz `0 ≤ v ≤ 1` e `v ≠ NaN`.
|
| 305 |
+
|
| 306 |
+
**Prova**: o campo é privado ⇒ construção só ocorre em (a) `novo`, que
|
| 307 |
+
devolve `Err` para `v ∉ [0,1] ∪ {NaN}`; (b) `complemento`, que produz
|
| 308 |
+
`1 − p` com p ∈ [0,1] ⇒ resultado em [0,1] (fechamento). Não há mutação
|
| 309 |
+
pública do campo. Por indução sobre as operações do tipo, todo valor
|
| 310 |
+
accessible satisfaz o invariante. ∎ **Testes**: tv1a (recusa −1e−12, −0,5,
|
| 311 |
+
1+1e−12, 7,0, NaN, ∞ em AMBOS os tipos), tv1b (aceita exatamente o
|
| 312 |
+
fechamento [0,1]), tv1c (fechamento do complemento).
|
| 313 |
+
|
| 314 |
+
### 6.3 Teo T-V2 (o gate tipado fecha em [0,1]) ∎
|
| 315 |
+
|
| 316 |
+
`g(π) = max(0, 2σ((π − θ_π)/τ_g) − 1)`: σ ∈ (0,1) ⇒ 2σ−1 ∈ (−1,1) ⇒
|
| 317 |
+
`max(0,·) ∈ [0,1)` para toda entrada REAL (nem precisa π ∈ [0,1]). Logo
|
| 318 |
+
`GatePunicao::valor_tipado(&Probabilidade) -> GateAtivacao` nunca falha no
|
| 319 |
+
construtor validado (o `expect` é coberto pela prova — o pânico é
|
| 320 |
+
impossível por construção). ∎ **Teste tv2**: varredura densa de 2001
|
| 321 |
+
pontos em [0,1], saída sempre em [0,1]; `valor` (f64 puro, caminho quente
|
| 322 |
+
sem alocação) permanece para compatibilidade.
|
| 323 |
+
|
| 324 |
+
### 6.4 Kani (verificação formal) — débito justificado
|
| 325 |
+
|
| 326 |
+
Kani verificaria invariantes por bounded model checking; para invariantes
|
| 327 |
+
de intervalo escalar com construtores de 2 linhas, o ganho sobre
|
| 328 |
+
T-V1 + testes de propriedade é marginal e o custo (toolchain dedicada,
|
| 329 |
+
análise por caminho) não se paga NESTA iteração. Registrado como débito
|
| 330 |
+
honesto (§10) — não como promessa cumprida.
|
| 331 |
+
|
| 332 |
+
---
|
| 333 |
+
|
| 334 |
+
## §7 — Nomenclatura: renomeação em massa REJEITADA (prova por quebra)
|
| 335 |
+
|
| 336 |
+
A crítica recomenda "padronização, preferencialmente inglês para código".
|
| 337 |
+
**Rejeitado com justificativa**: (a) a superfície pública PT-BR é
|
| 338 |
+
CONSUMIDA por 30+ scripts publicados (39–73) e pelos gates documentados —
|
| 339 |
+
renomear quebraria o contrato sem ganho de correção (viola "não remover
|
| 340 |
+
funcionalidade eficaz": a funcionalidade de compatibilidade); (b) o
|
| 341 |
+
projeto é declaradamente PT-BR (docs, memórias, logs, usuário); (c) a
|
| 342 |
+
inconsistência real (mistura fwd/forward) foi resolvida PONTUALMENTE:
|
| 343 |
+
`forward` adotado como nome canônico da passada (convenção universal de
|
| 344 |
+
ML), mantendo `fwd` deprecada como oráculo. Convenção documentada: **API
|
| 345 |
+
pública PT-BR; termos consagrados de ML em inglês quando são o nome
|
| 346 |
+
próprio da técnica (forward, softmax, gate); novos módulos seguem o
|
| 347 |
+
domínio.**
|
| 348 |
+
|
| 349 |
+
---
|
| 350 |
+
|
| 351 |
+
## §8 — Resultados consolidados
|
| 352 |
+
|
| 353 |
+
1. **skew**: 919× (n=128), memória 2.335× menor, bit-a-bit idêntico,
|
| 354 |
+
n=256 viável; gradiente íntegro (F-13/F-14).
|
| 355 |
+
2. **calibrar**: 1,56× mais rápida zero-cópia, bit-a-bit idêntica (F-15);
|
| 356 |
+
premissa da crítica refutada na CPU com análise do kernel no fonte.
|
| 357 |
+
3. **forward canônico**: API pública 100% íntegra em gradiente; valores
|
| 358 |
+
idênticos ao oráculo (0,0); 3 sítios remanescentes migrados.
|
| 359 |
+
4. **FFI isolada**: lib.rs 1,25 kB (83,6× menor); domínio testa sem
|
| 360 |
+
Python (107/107); overhead Python medido 17,6% (não 40%).
|
| 361 |
+
5. **newtypes**: T-V1/T-V2 provados e testados; errata da proposta Qwen
|
| 362 |
+
(campo público não prova nada).
|
| 363 |
+
6. **Suíte**: 85/85 gates herdados v0.8.0 + 12 novos = **97/97**
|
| 364 |
+
(suite_v090_final.json); cargo 107/107 × 3 execuções (determinismo).
|
| 365 |
+
7. **Dados reais**: pipeline A/B/C completo em Wikipédia PT-BR (1.121
|
| 366 |
+
sequências, build v0.9.0): fase C CE 3,9500 → 3,9293 (decrescente —
|
| 367 |
+
o registro v0.7.0 havia terminado 3,98, ACIMA do inicial); FNH com
|
| 368 |
+
punição real: gate abre (0,941), θ aprende (0,0426), δ_ort = 2,1e−07
|
| 369 |
+
(SO(n) exato); árvore de pesos invariantes OK. Leitura honesta: 180
|
| 370 |
+
passos de fase conjunta em CPU é orçamento de fumaça — a demonstração
|
| 371 |
+
é de INTEGRIDADE do pipeline com o build v0.9.0 e dos gates, não de
|
| 372 |
+
qualidade de geração (amostras greedy colapsam neste orçamento).
|
| 373 |
+
|
| 374 |
+
---
|
| 375 |
+
|
| 376 |
+
## §9 — Autocrítica: erros meus nesta iteração (causa-raiz)
|
| 377 |
+
|
| 378 |
+
| ID | Onde | Causa-raiz | Correção |
|
| 379 |
+
|----|------|-----------|----------|
|
| 380 |
+
| v090-1 | teste f14 (1ª versão) | perda ‖R‖²_F com θ=0 tem gradiente NULO por matemática (mínimo em R=I; A skew ⇒ tr=0) — teste "provava" bug inexistente | perda quadrática com θ≠0 + perda LINEAR em entrada única no nascimento (dR[0,1]/dθ₀=1); nota honesta no doc do teste |
|
| 381 |
+
| v090-2 | teste f14 (2ª versão) | Σ_ij R_ij também é cego a perturbação skew (Σ A_ij ≡ 0) — 2ª formulação errada | entrada ÚNICA R[0,1] via narrow+sum (grafo vivo) |
|
| 382 |
+
| v090-3 | max_abs_por_coluna (1ª versão) | `k % d` por elemento (~20 ciclos, bloqueia vetorização) — zero-cópia ficou 2,4× MAIS LENTA que a referência | `chunks_exact(d)` — 1,56× mais rápida |
|
| 383 |
+
| v090-4 | inserção da demo | replace de "#[pymodule]" casou com o TEXTO no comentário de cabeçalho — demo inserida antes dos `use` | reconstrução do cabeçalho + movimentação para antes do pymodule real |
|
| 384 |
+
| v090-5 | primeira medição calibrar | aceitei a premissa do Qwen ("kernels otimizados") sem medir — a versão tensor era 11× mais lenta | medição ANTES de promover a padrão; análise do kernel no fonte; desenho final zero-cópia + opt-in |
|
| 385 |
+
|
| 386 |
+
O processo analisar→provar→(MEDIR)→testar capturou v090-1/2/3 antes de
|
| 387 |
+
qualquer publicação. O v090-5 é o mais instrutivo: **premissa de crítica
|
| 388 |
+
externa também é hipótese a testar**.
|
| 389 |
+
|
| 390 |
+
## §10 — Débitos honestos remanescentes
|
| 391 |
+
|
| 392 |
+
1. `calibrar_tensor` não foi medida em GPU (ambiente sem GPU) — a análise
|
| 393 |
+
do §5.1 é específica da CPU; a recomendação do opt-in em backends
|
| 394 |
+
acelerados é teórica (fundamentada no round-trip eliminado).
|
| 395 |
+
2. Kani/verificação formal dos newtypes — deferred (§6.4).
|
| 396 |
+
3. A renomeação `forward` não tem alias `fwd_vetorizado` (consumidores
|
| 397 |
+
Rust externos à árvore quebram — aceito por ser pré-1.0 e o nome antigo
|
| 398 |
+
existir há UMA versão; scripts Python não usavam o nome).
|
| 399 |
+
4. Amostras greedy degeneradas no orçamento de treino real (§8.7) — a
|
| 400 |
+
qualidade de GERAÇÃO requer treino completo (horas de CPU), fora do
|
| 401 |
+
escopo desta iteração de refatoração.
|
| 402 |
+
5. O bug v080-1 persiste como ORÁCULO deprecated — remover
|
| 403 |
+
definitivamente os oráculos (fwd, calibrar_referencia,
|
| 404 |
+
skew_matmul_referencia) só quando os gates correspondentes forem
|
| 405 |
+
considerados permanentes.
|
pyproject.toml
CHANGED
|
@@ -4,12 +4,12 @@ build-backend = "maturin"
|
|
| 4 |
|
| 5 |
[project]
|
| 6 |
name = "khtst-rust"
|
| 7 |
-
version = "0.
|
| 8 |
-
description = "KHTST_RUST — NCM com verificador calibrado (
|
| 9 |
requires-python = ">=3.10"
|
| 10 |
license = { text = "Apache-2.0" }
|
| 11 |
|
| 12 |
[tool.maturin]
|
| 13 |
python-source = "python"
|
| 14 |
module-name = "khtst_rust.nucleo_rust"
|
| 15 |
-
features = ["pyo3/extension-module"]
|
|
|
|
| 4 |
|
| 5 |
[project]
|
| 6 |
name = "khtst-rust"
|
| 7 |
+
version = "0.9.0"
|
| 8 |
+
description = "KHTST_RUST — NCM com verificador calibrado, MoEs redirecionáveis com forward canônico (gradiente íntegro), FNH com skew O(n²) e calibração vetorial, FFI Python isolada em feature e newtypes de domínio (críticas Qwen3.8 analisadas/provadas/testadas em r-34)"
|
| 9 |
requires-python = ">=3.10"
|
| 10 |
license = { text = "Apache-2.0" }
|
| 11 |
|
| 12 |
[tool.maturin]
|
| 13 |
python-source = "python"
|
| 14 |
module-name = "khtst_rust.nucleo_rust"
|
| 15 |
+
features = ["python", "ponte_async", "pyo3/extension-module"]
|
resultados/gerador_conceitos.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c43a507268527be67e6ecd2d371dceb2e197d3bc79c6ce096e5c37d28d23adb4
|
| 3 |
+
size 59523968
|
resultados/suite_v090_final.json
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"versao": "0.9.0",
|
| 3 |
+
"blocos": {
|
| 4 |
+
"legado_v080": "85/85",
|
| 5 |
+
"q1_skew_index_add": "1/1",
|
| 6 |
+
"q2_calibrar_zero_copia": "2/2",
|
| 7 |
+
"q3_forward_canonico": "1/1",
|
| 8 |
+
"q4_newtypes": "1/1",
|
| 9 |
+
"treino_real_v090": "4/4",
|
| 10 |
+
"q5_split_ffi": "1/1"
|
| 11 |
+
},
|
| 12 |
+
"gates": {
|
| 13 |
+
"legado_legado_legado_calibracao_soundness.v1_calibracao": true,
|
| 14 |
+
"legado_legado_legado_calibracao_soundness.v2_soundness": true,
|
| 15 |
+
"legado_legado_legado_calibracao_soundness.v3_tau_positivo": true,
|
| 16 |
+
"legado_legado_legado_ciclo_d_sem_oraculo.aprendeu": true,
|
| 17 |
+
"legado_legado_legado_ciclo_d_sem_oraculo.terminou": true,
|
| 18 |
+
"legado_legado_legado_ciclo_d_sem_oraculo.sem_oraculo": true,
|
| 19 |
+
"legado_legado_legado_ciclo_d_sem_oraculo.calibrado": true,
|
| 20 |
+
"legado_legado_legado_ciclo_d_sem_oraculo.ganho_nao_negativo": true,
|
| 21 |
+
"legado_legado_legado_ciclo_d_sem_oraculo.verificador_sem_oraculo": true,
|
| 22 |
+
"legado_legado_legado_escalonamento_n.tp2_ncm": true,
|
| 23 |
+
"legado_legado_legado_fase_c.verificador_sem_oraculo": true,
|
| 24 |
+
"legado_legado_legado_fase_c.calibracao_nll_otima": true,
|
| 25 |
+
"legado_legado_legado_fase_c.ece_aceitavel_para_soundness": true,
|
| 26 |
+
"legado_legado_legado_fase_c.correcao_ativa": true,
|
| 27 |
+
"legado_legado_legado_fase_c.acoplador_sem_timeout": true,
|
| 28 |
+
"legado_legado_legado_fase_c.acoplador_duplex_ativo": true,
|
| 29 |
+
"legado_legado_legado_fase_c.confianca_pos_nao_inferior": true,
|
| 30 |
+
"legado_legado_legado_fase_c.backbone_preservado": true,
|
| 31 |
+
"legado_legado_legado_fase_c.pcgrad_sem_conflito_observado": true,
|
| 32 |
+
"legado_legado_legado_provas_mr.mr1_capacidade": true,
|
| 33 |
+
"legado_legado_legado_provas_mr.mr1_perda_aux": true,
|
| 34 |
+
"legado_legado_legado_provas_mr.mr2_neutralidade": true,
|
| 35 |
+
"legado_legado_legado_provas_mr.mr3_paralelismo": true,
|
| 36 |
+
"legado_legado_legado_provas_mr.mr5_water_filling": true,
|
| 37 |
+
"legado_legado_legado_jepa_moe.jepa_moe_aprende": true,
|
| 38 |
+
"legado_legado_legado_jepa_moe.jepa_moe_vs_densa": true,
|
| 39 |
+
"legado_legado_legado_jepa_moe.jepa_moe_vs_pequena": true,
|
| 40 |
+
"legado_legado_legado_som_moe.moe_refina": true,
|
| 41 |
+
"legado_legado_legado_som_moe.redirect_decodifica": true,
|
| 42 |
+
"legado_legado_legado_som_moe.wf_melhor_uniforme": true,
|
| 43 |
+
"legado_legado_legado_acoplador_duplo.duplex_simultaneo": true,
|
| 44 |
+
"legado_legado_legado_acoplador_duplo.sem_timeout": true,
|
| 45 |
+
"legado_legado_legado_acoplador_duplo.terminou": true,
|
| 46 |
+
"legado_legado_legado_iter.gate_ucb1_encontrou_moe": true,
|
| 47 |
+
"legado_legado_legado_iter.gate_gap_positivo_vs_baseline": true,
|
| 48 |
+
"legado_legado_legado_iter.gate_arrependimento_pequeno": true,
|
| 49 |
+
"legado_legado_legado_iter.gate_regulacao_ocorreu": true,
|
| 50 |
+
"legado_legado_legado_iter.gate_parada_ou_teto": true,
|
| 51 |
+
"legado_legado_legado_iter.gate_melhor_aprendeu": true,
|
| 52 |
+
"legado_legado_legado_iter.a1_tau_quantil": true,
|
| 53 |
+
"legado_legado_legado_iter.a2_b_finito": true,
|
| 54 |
+
"legado_legado_legado_iter.a3_n_reduzido": true,
|
| 55 |
+
"legado_legado_legado_iter.a4_ucb1_achou": true,
|
| 56 |
+
"legado_legado_legado_iter.a5_gate_subiu": true,
|
| 57 |
+
"legado_legado_legado_legada_suite_v": true,
|
| 58 |
+
"legado_legado_legado_cargo_54": true,
|
| 59 |
+
"legado_legado_fnh_f1_so_n_exato": true,
|
| 60 |
+
"legado_legado_fnh_f3_gate_zona_morta": true,
|
| 61 |
+
"legado_legado_fnh_f3_gate_abre": true,
|
| 62 |
+
"legado_legado_fnh_f4_homeostase_theta_congelado": true,
|
| 63 |
+
"legado_legado_fnh_f4_rotacao_aprende_com_punicao": true,
|
| 64 |
+
"legado_legado_fnh_a2_delta_ort_treino_real": true,
|
| 65 |
+
"legado_legado_fnh_a3_punicao_real_medida": true,
|
| 66 |
+
"legado_legado_arvore_quebra_t1_invariantes": true,
|
| 67 |
+
"legado_legado_arvore_quebra_t2_agregacao_exata": true,
|
| 68 |
+
"legado_legado_arvore_quebra_t3_teto_simetrico": true,
|
| 69 |
+
"legado_legado_arvore_quebra_q1_executa_real": true,
|
| 70 |
+
"legado_legado_arvore_quebra_q2_soundness_aceites": true,
|
| 71 |
+
"legado_legado_arvore_quebra_q3_invariantes_pos_quebra": true,
|
| 72 |
+
"legado_legado_arvore_quebra_q4_punicao_registrada": true,
|
| 73 |
+
"legado_legado_arvore_quebra_q5_sintetico_mistura_aceita_rejeita": true,
|
| 74 |
+
"legado_legado_nlp_nlg_n_coerencia_ok": true,
|
| 75 |
+
"legado_legado_nlp_nlg_n_espec_ok": true,
|
| 76 |
+
"legado_legado_nlp_nlg_n_gate_medio_ok": true,
|
| 77 |
+
"legado_legado_nlp_nlg_n_nlg_neutro": true,
|
| 78 |
+
"legado_legado_nlp_nlg_n_nlp_neutro": true,
|
| 79 |
+
"legado_legado_nlp_nlg_n_ctx_real_bigramas_unicos": true,
|
| 80 |
+
"legado_legado_nlp_nlg_s_piso_ok": true,
|
| 81 |
+
"legado_legado_nlp_nlg_s_qe_sobe": true,
|
| 82 |
+
"legado_legado_nlp_nlg_s_stop_dispara": true,
|
| 83 |
+
"legado_legado_nlp_nlg_s_tetos_ok": true,
|
| 84 |
+
"legado_legado_telemetria_painel_v070": true,
|
| 85 |
+
"legado_legado_treino_real_completo": true,
|
| 86 |
+
"legado_q1_newton_menos_avaliacoes": true,
|
| 87 |
+
"legado_q1_newton_mesmo_t": true,
|
| 88 |
+
"legado_q1_newton_nll_nao_piora": true,
|
| 89 |
+
"legado_q3_cayley_ambos_exatos": true,
|
| 90 |
+
"legado_q3_cayley_cayley_mais_rapido": true,
|
| 91 |
+
"legado_q2_arvore_iguais_bit_a_bit": true,
|
| 92 |
+
"legado_q4_moe_bug_v080_1_confirmado": true,
|
| 93 |
+
"legado_q4_moe_gradiente_restaurado": true,
|
| 94 |
+
"legado_q4_moe_valores_iguais": true,
|
| 95 |
+
"legado_q5_ablacao_moe_aprende_3x": true,
|
| 96 |
+
"legado_q5_ablacao_moe_domina_pequena_3x": true,
|
| 97 |
+
"legado_cargo_todos_verdes": true,
|
| 98 |
+
"q1_skew_bits_identicos": true,
|
| 99 |
+
"q1_skew_mais_rapido_n128": true,
|
| 100 |
+
"q2_calibrar_bit_a_bit": true,
|
| 101 |
+
"q2_calibrar_nao_regride": true,
|
| 102 |
+
"q3_forward_valores_e_gradiente": true,
|
| 103 |
+
"q4_newtypes_fronteira_validada": true,
|
| 104 |
+
"real_gate_abre_com_punicao_alta": true,
|
| 105 |
+
"real_gate_fecha_com_punicao_baixa": true,
|
| 106 |
+
"real_rotacao_aprende": true,
|
| 107 |
+
"real_so_n_exato": true,
|
| 108 |
+
"real_ce_decresce": true,
|
| 109 |
+
"q5_compila_sem_python": true
|
| 110 |
+
},
|
| 111 |
+
"medicoes": {
|
| 112 |
+
"q1_skew": {
|
| 113 |
+
"n_16": {
|
| 114 |
+
"speedup": 5.953761530968888,
|
| 115 |
+
"razao_memoria": 35.88785046728972,
|
| 116 |
+
"tempo_novo_s": 3.4906e-06,
|
| 117 |
+
"tempo_ref_s": 2.11814e-05
|
| 118 |
+
},
|
| 119 |
+
"n_64": {
|
| 120 |
+
"speedup": 128.06781482163692,
|
| 121 |
+
"razao_memoria": 582.5011286681715,
|
| 122 |
+
"tempo_novo_s": 2.61382e-05,
|
| 123 |
+
"tempo_ref_s": 0.0033373448
|
| 124 |
+
},
|
| 125 |
+
"n_128": {
|
| 126 |
+
"speedup": 904.1866934950408,
|
| 127 |
+
"razao_memoria": 2335.317620650954,
|
| 128 |
+
"tempo_novo_s": 0.0001012268,
|
| 129 |
+
"tempo_ref_s": 0.0915812726
|
| 130 |
+
}
|
| 131 |
+
},
|
| 132 |
+
"q2_calibrar": {
|
| 133 |
+
"tempo_ref_s": 0.0017999709999999998,
|
| 134 |
+
"tempo_novo_s": 0.0011533832,
|
| 135 |
+
"tempo_tensor_s": 0.020109004,
|
| 136 |
+
"speedup_zero_copia": 1.5606010214124844,
|
| 137 |
+
"razao_tensor_vs_zero_copia": 17.434798772862305
|
| 138 |
+
},
|
| 139 |
+
"q3_forward": {
|
| 140 |
+
"max_dif_valores_vs_oraculo": 0.0,
|
| 141 |
+
"grad_roteador": 139952.28125,
|
| 142 |
+
"grad_especialistas": 2042232.265625
|
| 143 |
+
},
|
| 144 |
+
"treino_real": {
|
| 145 |
+
"sequencias": 1121,
|
| 146 |
+
"fonte": "wikimedia/wikipedia 20231101.pt",
|
| 147 |
+
"ce_inicial": 3.9499684742518832,
|
| 148 |
+
"ce_final": 3.9293200288500105,
|
| 149 |
+
"build": "khtst-rust-0.9.0"
|
| 150 |
+
},
|
| 151 |
+
"q5_compilacao": {
|
| 152 |
+
"dominio_compila": true,
|
| 153 |
+
"tempo_frio_dominio_s": 70,
|
| 154 |
+
"tempo_frio_completo_s": 85,
|
| 155 |
+
"overhead_python_pct": 17.6,
|
| 156 |
+
"nota": "alegação Qwen '≈40%' CORRIGIDA por medição: overhead real desta máquina ~18% (70s vs 85s, builds frios com candle igual)"
|
| 157 |
+
}
|
| 158 |
+
}
|
| 159 |
+
}
|
resultados/telemetria_fase_c.jsonl
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
resultados/telemetria_v090.json
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"versao": "0.9.0",
|
| 3 |
+
"estrutura": {
|
| 4 |
+
"lib_rs_bytes": 1250,
|
| 5 |
+
"lib_rs_bytes_v080": 104558,
|
| 6 |
+
"python_rs_bytes": 112410,
|
| 7 |
+
"razao_de_tamanho": 83.6,
|
| 8 |
+
"modulos_dominio": 33,
|
| 9 |
+
"pyfunctions": 42,
|
| 10 |
+
"pyclasses": 1,
|
| 11 |
+
"deps_mortas_removidas": [
|
| 12 |
+
"numpy 0.23 (0 usos)",
|
| 13 |
+
"dict_derive 0.5 (0 usos)",
|
| 14 |
+
"pyo3-built 0.5 (0 usos)"
|
| 15 |
+
],
|
| 16 |
+
"dominio_importa_pyo3": false,
|
| 17 |
+
"arquivos_fonte": 34
|
| 18 |
+
},
|
| 19 |
+
"compilacao": {
|
| 20 |
+
"dominio_compila": true,
|
| 21 |
+
"tempo_frio_dominio_s": 70,
|
| 22 |
+
"tempo_frio_completo_s": 85,
|
| 23 |
+
"overhead_python_pct": 17.6,
|
| 24 |
+
"nota": "alegação Qwen '≈40%' CORRIGIDA por medição: overhead real desta máquina ~18% (70s vs 85s, builds frios com candle igual)"
|
| 25 |
+
},
|
| 26 |
+
"testes": {
|
| 27 |
+
"cargo_dominio_sem_python": "105+2 = 107/107",
|
| 28 |
+
"cargo_completo": "105+2 = 107/107",
|
| 29 |
+
"determinismo": "3 execuções idênticas",
|
| 30 |
+
"herdados_v080": 99,
|
| 31 |
+
"novos_v090": 8,
|
| 32 |
+
"novos": [
|
| 33 |
+
"f13_skew_bit_a_bit",
|
| 34 |
+
"f14_skew_gradiente_e_escala",
|
| 35 |
+
"sq1_calibrar_bit_a_bit",
|
| 36 |
+
"sq2_calibrar_smoke",
|
| 37 |
+
"tv1a_construtor_recusa",
|
| 38 |
+
"tv1b_construtor_aceita",
|
| 39 |
+
"tv1c_complemento",
|
| 40 |
+
"tv2_gate_tipado_dominio"
|
| 41 |
+
]
|
| 42 |
+
},
|
| 43 |
+
"modulos": {
|
| 44 |
+
"acoplador.rs": 7940,
|
| 45 |
+
"amostrador.rs": 13407,
|
| 46 |
+
"arvore_pesos.rs": 27829,
|
| 47 |
+
"atencao.rs": 8619,
|
| 48 |
+
"camadas.rs": 4493,
|
| 49 |
+
"config.rs": 10411,
|
| 50 |
+
"controlador.rs": 25287,
|
| 51 |
+
"diagnostico.rs": 11047,
|
| 52 |
+
"fnh.rs": 57371,
|
| 53 |
+
"gerador.rs": 11809,
|
| 54 |
+
"jepa.rs": 58407,
|
| 55 |
+
"lib.rs": 1250,
|
| 56 |
+
"mascaras.rs": 5427,
|
| 57 |
+
"memoria.rs": 5281,
|
| 58 |
+
"moe_redirecionavel.rs": 50941,
|
| 59 |
+
"nlg.rs": 18288,
|
| 60 |
+
"nlp.rs": 10280,
|
| 61 |
+
"pensamento.rs": 53408,
|
| 62 |
+
"perdas.rs": 4861,
|
| 63 |
+
"ponte.rs": 9317,
|
| 64 |
+
"python.rs": 112410,
|
| 65 |
+
"quantizacao.rs": 2496,
|
| 66 |
+
"quantizador.rs": 16123,
|
| 67 |
+
"rng.rs": 5962,
|
| 68 |
+
"som4d.rs": 37160,
|
| 69 |
+
"ssd.rs": 7625,
|
| 70 |
+
"stiefel.rs": 7411,
|
| 71 |
+
"telemetria.rs": 18450,
|
| 72 |
+
"tipos.rs": 4510,
|
| 73 |
+
"tokenizador.rs": 19225,
|
| 74 |
+
"tokens.rs": 9977,
|
| 75 |
+
"treino.rs": 46987,
|
| 76 |
+
"tronco.rs": 10125,
|
| 77 |
+
"verificador.rs": 24821
|
| 78 |
+
},
|
| 79 |
+
"api": {
|
| 80 |
+
"deprecados": [
|
| 81 |
+
"MoeRedirecionavel::fwd (pub(crate), bug v080-1 — oráculo de testes)"
|
| 82 |
+
],
|
| 83 |
+
"renomeados": {
|
| 84 |
+
"fwd_vetorizado": "forward"
|
| 85 |
+
},
|
| 86 |
+
"opt_in": [
|
| 87 |
+
"SuavizadorQuant::calibrar_tensor (backends acelerados)"
|
| 88 |
+
],
|
| 89 |
+
"removidos_da_api_publica": []
|
| 90 |
+
}
|
| 91 |
+
}
|
resultados/tokenizador_conceitos.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:16f7165ab1e7ea398b6265a092839f206353ad4980cfc9b750547e683d1a1b07
|
| 3 |
+
size 240887483
|
resultados/treino_v090.json
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"versao": "0.9.0",
|
| 3 |
+
"build": "khtst-rust-0.9.0",
|
| 4 |
+
"dados": {
|
| 5 |
+
"sequencias": 1121,
|
| 6 |
+
"fonte": "wikimedia/wikipedia 20231101.pt"
|
| 7 |
+
},
|
| 8 |
+
"fases": {
|
| 9 |
+
"c": {
|
| 10 |
+
"acordos_medios": 0.5188963732356818,
|
| 11 |
+
"ce_final": 3.9293200288500105,
|
| 12 |
+
"ce_gatilhada_com_correcao": 4.091411646335356,
|
| 13 |
+
"ce_gatilhada_sem_correcao": 4.073794892270078,
|
| 14 |
+
"ce_inicial": 3.9499684742518832,
|
| 15 |
+
"confianca_media_final": 0.0002814010949805379,
|
| 16 |
+
"confianca_media_inicial": 0.00025644380366429687,
|
| 17 |
+
"confianca_pos_correcao": 0.0002146976511745203,
|
| 18 |
+
"decaimento_delta": 0.8004814077785324,
|
| 19 |
+
"ece_antes": 0.0153643210651353,
|
| 20 |
+
"ece_depois": 0.002648286405019462,
|
| 21 |
+
"escore_aprendizado": 0.20041952236591176,
|
| 22 |
+
"maior_sobreposicao_us": 5,
|
| 23 |
+
"passos": 169,
|
| 24 |
+
"rodadas_acoplador": 155,
|
| 25 |
+
"tau_c": 0.015690743923187256,
|
| 26 |
+
"taxa_conflito_pcgrad": 0.0,
|
| 27 |
+
"taxa_gatilho": 0.6020710059171598,
|
| 28 |
+
"temperatura_calibrada": 8.0,
|
| 29 |
+
"timeouts_acoplador": 0,
|
| 30 |
+
"tempo_s": 403.8611032962799
|
| 31 |
+
}
|
| 32 |
+
},
|
| 33 |
+
"arvore": {
|
| 34 |
+
"invariantes": true,
|
| 35 |
+
"total_confianca": 0.0,
|
| 36 |
+
"total_punicao": 0.0,
|
| 37 |
+
"dump": {
|
| 38 |
+
"invariantes_ok": true,
|
| 39 |
+
"n_nos": 12,
|
| 40 |
+
"n_params": 14370000,
|
| 41 |
+
"nos": [
|
| 42 |
+
{
|
| 43 |
+
"fim": 0,
|
| 44 |
+
"ini": 0,
|
| 45 |
+
"metricas": {
|
| 46 |
+
"confianca": 0.0,
|
| 47 |
+
"punicao": 0.0
|
| 48 |
+
},
|
| 49 |
+
"nome": "khtst",
|
| 50 |
+
"profundidade": 0
|
| 51 |
+
},
|
| 52 |
+
{
|
| 53 |
+
"fim": 10000000,
|
| 54 |
+
"ini": 0,
|
| 55 |
+
"metricas": {
|
| 56 |
+
"confianca": 0.0,
|
| 57 |
+
"punicao": 0.0
|
| 58 |
+
},
|
| 59 |
+
"nome": "tronco",
|
| 60 |
+
"profundidade": 1
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"fim": 11200000,
|
| 64 |
+
"ini": 10000000,
|
| 65 |
+
"metricas": {
|
| 66 |
+
"confianca": 0.0,
|
| 67 |
+
"perda": 0.0,
|
| 68 |
+
"punicao": 0.0
|
| 69 |
+
},
|
| 70 |
+
"nome": "quantizador",
|
| 71 |
+
"profundidade": 1
|
| 72 |
+
},
|
| 73 |
+
{
|
| 74 |
+
"fim": 11500000,
|
| 75 |
+
"ini": 11200000,
|
| 76 |
+
"metricas": {
|
| 77 |
+
"confianca": 0.0,
|
| 78 |
+
"punicao": 0.0
|
| 79 |
+
},
|
| 80 |
+
"nome": "som",
|
| 81 |
+
"profundidade": 1
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"fim": 12400000,
|
| 85 |
+
"ini": 11500000,
|
| 86 |
+
"metricas": {
|
| 87 |
+
"confianca": 0.0,
|
| 88 |
+
"punicao": 0.0
|
| 89 |
+
},
|
| 90 |
+
"nome": "jepa",
|
| 91 |
+
"profundidade": 1
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"fim": 13200000,
|
| 95 |
+
"ini": 12400000,
|
| 96 |
+
"metricas": {
|
| 97 |
+
"confianca": 0.0,
|
| 98 |
+
"punicao": 0.0
|
| 99 |
+
},
|
| 100 |
+
"nome": "moe",
|
| 101 |
+
"profundidade": 1
|
| 102 |
+
},
|
| 103 |
+
{
|
| 104 |
+
"fim": 13600000,
|
| 105 |
+
"ini": 13200000,
|
| 106 |
+
"metricas": {
|
| 107 |
+
"confianca": 0.0,
|
| 108 |
+
"punicao": 0.0
|
| 109 |
+
},
|
| 110 |
+
"nome": "pensamento",
|
| 111 |
+
"profundidade": 1
|
| 112 |
+
},
|
| 113 |
+
{
|
| 114 |
+
"fim": 13610000,
|
| 115 |
+
"ini": 13600000,
|
| 116 |
+
"metricas": {
|
| 117 |
+
"confianca": 0.0,
|
| 118 |
+
"punicao": 0.0
|
| 119 |
+
},
|
| 120 |
+
"nome": "verificador",
|
| 121 |
+
"profundidade": 1
|
| 122 |
+
},
|
| 123 |
+
{
|
| 124 |
+
"fim": 13760000,
|
| 125 |
+
"ini": 13610000,
|
| 126 |
+
"metricas": {
|
| 127 |
+
"confianca": 0.0,
|
| 128 |
+
"punicao": 0.0
|
| 129 |
+
},
|
| 130 |
+
"nome": "fnh",
|
| 131 |
+
"profundidade": 1
|
| 132 |
+
},
|
| 133 |
+
{
|
| 134 |
+
"fim": 14060000,
|
| 135 |
+
"ini": 13760000,
|
| 136 |
+
"metricas": {
|
| 137 |
+
"confianca": 0.0,
|
| 138 |
+
"punicao": 0.0
|
| 139 |
+
},
|
| 140 |
+
"nome": "nlp",
|
| 141 |
+
"profundidade": 1
|
| 142 |
+
},
|
| 143 |
+
{
|
| 144 |
+
"fim": 14310000,
|
| 145 |
+
"ini": 14060000,
|
| 146 |
+
"metricas": {
|
| 147 |
+
"confianca": 0.0,
|
| 148 |
+
"perda": 0.0,
|
| 149 |
+
"punicao": 0.0
|
| 150 |
+
},
|
| 151 |
+
"nome": "nlg",
|
| 152 |
+
"profundidade": 1
|
| 153 |
+
},
|
| 154 |
+
{
|
| 155 |
+
"fim": 14370000,
|
| 156 |
+
"ini": 14310000,
|
| 157 |
+
"metricas": {
|
| 158 |
+
"confianca": 0.0,
|
| 159 |
+
"punicao": 0.0
|
| 160 |
+
},
|
| 161 |
+
"nome": "acoplador",
|
| 162 |
+
"profundidade": 1
|
| 163 |
+
}
|
| 164 |
+
]
|
| 165 |
+
}
|
| 166 |
+
},
|
| 167 |
+
"fnh": {
|
| 168 |
+
"punicao_normalizada_fase_c": 0.0,
|
| 169 |
+
"abacao_sintetica": {
|
| 170 |
+
"punicao_alta": {
|
| 171 |
+
"delta_ort": 2.064895173658083e-07,
|
| 172 |
+
"gate_final": 0.9413755384972873,
|
| 173 |
+
"perda_final": 0.02014596201479435,
|
| 174 |
+
"perda_inicial": 0.02049672044813633,
|
| 175 |
+
"theta_norma": 0.042591993338429654
|
| 176 |
+
},
|
| 177 |
+
"punicao_baixa": {
|
| 178 |
+
"delta_ort": 0.0,
|
| 179 |
+
"gate_final": 0.0,
|
| 180 |
+
"perda_final": 0.022267581894993782,
|
| 181 |
+
"perda_inicial": 0.02211258001625538,
|
| 182 |
+
"theta_norma": 0.0
|
| 183 |
+
}
|
| 184 |
+
},
|
| 185 |
+
"gates": {
|
| 186 |
+
"gate_abre_com_punicao_alta": true,
|
| 187 |
+
"gate_fecha_com_punicao_baixa": true,
|
| 188 |
+
"rotacao_aprende": true,
|
| 189 |
+
"so_n_exato": true
|
| 190 |
+
}
|
| 191 |
+
}
|
| 192 |
+
}
|
scripts/70_coleta_shards_v090.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""70_coleta_shards_v090.py — re-coleta os shards REAIS (Wikipédia PT-BR)
|
| 3 |
+
para a validação v0.9.0 em dados reais. NÃO re-treina o BPE (dados/bpe.json
|
| 4 |
+
já existe — só os shards tinham sido apagados na limpeza de estados).
|
| 5 |
+
|
| 6 |
+
Tetos duros idênticos ao 39_coletar_dados.py (max_artigos/max_bytes do
|
| 7 |
+
config): streaming controlado, sem cache global do datasets."""
|
| 8 |
+
import json, os, sys, time
|
| 9 |
+
|
| 10 |
+
TETO_PADRAO_ARTIGOS = 1200
|
| 11 |
+
TETO_PADRAO_BYTES = 6_000_000
|
| 12 |
+
|
| 13 |
+
def main():
|
| 14 |
+
pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 15 |
+
cfg = json.load(open(os.path.join(pasta, "configs", "base_rust.json")))
|
| 16 |
+
dados_cfg = cfg.get("dados", {})
|
| 17 |
+
max_artigos = int(dados_cfg.get("max_artigos", TETO_PADRAO_ARTIGOS))
|
| 18 |
+
max_bytes = int(dados_cfg.get("max_bytes", TETO_PADRAO_BYTES))
|
| 19 |
+
os.makedirs(os.path.join(pasta, "dados"), exist_ok=True)
|
| 20 |
+
|
| 21 |
+
from datasets import load_dataset
|
| 22 |
+
t0 = time.time()
|
| 23 |
+
ds = load_dataset("wikimedia/wikipedia", "20231101.pt", split="train", streaming=True)
|
| 24 |
+
textos, total_bytes = [], 0
|
| 25 |
+
for ex in ds:
|
| 26 |
+
t = (ex.get("text") or "").strip()
|
| 27 |
+
if len(t) < 200:
|
| 28 |
+
continue
|
| 29 |
+
textos.append(t)
|
| 30 |
+
total_bytes += len(t.encode("utf-8"))
|
| 31 |
+
if len(textos) % 200 == 0:
|
| 32 |
+
print(f" ... {len(textos)} artigos, {total_bytes/1e6:.2f} MB", flush=True)
|
| 33 |
+
if len(textos) >= max_artigos or total_bytes >= max_bytes:
|
| 34 |
+
break
|
| 35 |
+
print(f"coletado: {len(textos)} artigos, {total_bytes/1e6:.2f} MB em {time.time()-t0:.1f}s")
|
| 36 |
+
|
| 37 |
+
def limpa(t: str) -> str:
|
| 38 |
+
partes = [p.strip() for p in t.split("\n") if len(p.strip()) > 80]
|
| 39 |
+
return " ".join(partes[:6])[:1800]
|
| 40 |
+
|
| 41 |
+
textos = [limpa(t) for t in textos]
|
| 42 |
+
n_val = max(1, len(textos) // 10)
|
| 43 |
+
val, treino = textos[:n_val], textos[n_val:]
|
| 44 |
+
with open(os.path.join(pasta, "dados", "shard_treino.jsonl"), "w") as f:
|
| 45 |
+
for t in treino:
|
| 46 |
+
f.write(json.dumps({"texto": t}, ensure_ascii=False) + "\n")
|
| 47 |
+
with open(os.path.join(pasta, "dados", "shard_validacao.jsonl"), "w") as f:
|
| 48 |
+
for t in val:
|
| 49 |
+
f.write(json.dumps({"texto": t}, ensure_ascii=False) + "\n")
|
| 50 |
+
print(f"shards: treino={len(treino)} val={len(val)} (bpe.json preservado)")
|
| 51 |
+
|
| 52 |
+
if __name__ == "__main__":
|
| 53 |
+
main()
|
scripts/71_treino_v090.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""71_treino_v090.py — v0.9.0: treino REAL (fases A/B/C) com o build v0.9.0
|
| 3 |
+
(skew O(n²), calibrar zero-cópia, forward canônico) — demonstra alta
|
| 4 |
+
qualidade de aprendizado em dados reais (Wikipédia PT-BR) e verifica que a
|
| 5 |
+
refatoração FFI/feature não regrediu NADA no pipeline.
|
| 6 |
+
|
| 7 |
+
Resiliente a mortes de processo (o fundo pode matar sem erro/OOM):
|
| 8 |
+
fase A grava tokenizador_conceitos.json; fase B grava
|
| 9 |
+
gerador_conceitos.json; fase C extrai métricas da telemetria se o dump
|
| 10 |
+
final existir (resume). Re-executar o script continua de onde parou.
|
| 11 |
+
Saída: resultados/treino_v090.json
|
| 12 |
+
"""
|
| 13 |
+
import json, os, sys, time
|
| 14 |
+
|
| 15 |
+
CONTAGENS = { # estimativas documentadas (a árvore INDEXA; métricas medem)
|
| 16 |
+
"tronco": 10_000_000, "quantizador": 1_200_000, "som": 300_000,
|
| 17 |
+
"jepa": 900_000, "moe": 800_000, "pensamento": 400_000,
|
| 18 |
+
"verificador": 10_000, "fnh": 150_000, "nlp": 300_000,
|
| 19 |
+
"nlg": 250_000, "acoplador": 60_000,
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
def extrai_fase_c(caminho):
|
| 23 |
+
with open(caminho) as f:
|
| 24 |
+
linhas = [json.loads(l) for l in f]
|
| 25 |
+
dumps = [l["dados"] for l in linhas if l.get("tipo") == "dump"]
|
| 26 |
+
if not dumps:
|
| 27 |
+
return None
|
| 28 |
+
d = dumps[-1]
|
| 29 |
+
def serie(k):
|
| 30 |
+
return d.get(k, []) if isinstance(d.get(k), list) else []
|
| 31 |
+
def v(k, i=-1):
|
| 32 |
+
s = serie(k)
|
| 33 |
+
return s[i][1] if s else 0.0
|
| 34 |
+
n_passos = len(serie("perda"))
|
| 35 |
+
return {
|
| 36 |
+
"passos": n_passos,
|
| 37 |
+
"ce_inicial": v("perda", 0), "ce_final": v("perda"),
|
| 38 |
+
"ce_gatilhada_com_final": v("ce_gatilhada_com"),
|
| 39 |
+
"ce_gatilhada_sem_final": v("ce_gatilhada_sem"),
|
| 40 |
+
"confianca_inicial": v("confianca_media", 0),
|
| 41 |
+
"confianca_final": v("confianca_media"),
|
| 42 |
+
"confianca_pos_correcao_final": v("confianca_pos_correcao"),
|
| 43 |
+
"taxa_gatilho_media": (sum(x[1] for x in serie("taxa_gatilho"))
|
| 44 |
+
/ max(1, len(serie("taxa_gatilho")))),
|
| 45 |
+
"ece_final": v("ece_pos_calibracao"),
|
| 46 |
+
"temperatura_calibrada": v("temperatura_calibrada"),
|
| 47 |
+
"norma_grad_final": v("norma_grad"),
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
def main():
|
| 51 |
+
pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 52 |
+
sys.path.insert(0, pasta)
|
| 53 |
+
os.makedirs(os.path.join(pasta, "resultados"), exist_ok=True)
|
| 54 |
+
import khtst_rust as K
|
| 55 |
+
|
| 56 |
+
cfg = K.Config(os.path.join(pasta, "configs", "base_rust.json"))
|
| 57 |
+
ck_tok = os.path.join(pasta, "resultados", "tokenizador_conceitos.json")
|
| 58 |
+
ck_ger = os.path.join(pasta, "resultados", "gerador_conceitos.json")
|
| 59 |
+
tel_c = os.path.join(pasta, "resultados", "telemetria_fase_c.jsonl")
|
| 60 |
+
|
| 61 |
+
bpe = K.Bpe.carregar(os.path.join(pasta, "dados", "bpe.json"))
|
| 62 |
+
seqs = []
|
| 63 |
+
with open(os.path.join(pasta, "dados", "shard_treino.jsonl")) as f:
|
| 64 |
+
for linha in f:
|
| 65 |
+
ids = bpe.codificar(json.loads(linha)["texto"])
|
| 66 |
+
for i in range(0, max(1, len(ids) - 256), 128):
|
| 67 |
+
seqs.append(ids[i:i + 256])
|
| 68 |
+
seqs = seqs[:1400]
|
| 69 |
+
rel = {"versao": "0.9.0", "build": K.versao(), "dados": {
|
| 70 |
+
"sequencias": len(seqs), "fonte": "wikimedia/wikipedia 20231101.pt"},
|
| 71 |
+
"fases": {}}
|
| 72 |
+
print(f"sequências de treino: {len(seqs)} (ctx=256) | {K.versao()}", flush=True)
|
| 73 |
+
|
| 74 |
+
if not os.path.exists(ck_tok):
|
| 75 |
+
print("=== FASE A — tokenizador (GSQ+RCO Stiefel) ===", flush=True)
|
| 76 |
+
t0 = time.time()
|
| 77 |
+
saida = K.treinar_fase_a(cfg, seqs, caminho_telemetria=None,
|
| 78 |
+
caminho_checkpoint=ck_tok)
|
| 79 |
+
rel["fases"]["a"] = {**saida["resumo"], "tempo_s": time.time() - t0}
|
| 80 |
+
print(f" perda {rel['fases']['a']['perda_inicial']:.4f} -> "
|
| 81 |
+
f"{rel['fases']['a']['perda_final']:.4f} em {rel['fases']['a']['tempo_s']:.0f}s", flush=True)
|
| 82 |
+
else:
|
| 83 |
+
print("fase A: checkpoint presente — reutilizando", flush=True)
|
| 84 |
+
|
| 85 |
+
if not os.path.exists(ck_ger):
|
| 86 |
+
print("=== FASE B — gerador NCM ===", flush=True)
|
| 87 |
+
t0 = time.time()
|
| 88 |
+
saida_b = K.treinar_fase_b(cfg, seqs, caminho_tokenizador=ck_tok,
|
| 89 |
+
caminho_telemetria=None,
|
| 90 |
+
caminho_checkpoint=ck_ger, teto_seg=280.0)
|
| 91 |
+
rel["fases"]["b"] = {**saida_b["resumo"], "tempo_s": time.time() - t0}
|
| 92 |
+
print(f" perda {rel['fases']['b']['perda_inicial']:.4f} -> "
|
| 93 |
+
f"{rel['fases']['b']['perda_final']:.4f} em {rel['fases']['b']['tempo_s']:.0f}s", flush=True)
|
| 94 |
+
else:
|
| 95 |
+
print("fase B: checkpoint presente — reutilizando", flush=True)
|
| 96 |
+
|
| 97 |
+
resume = None
|
| 98 |
+
if os.path.exists(tel_c):
|
| 99 |
+
resume = extrai_fase_c(tel_c)
|
| 100 |
+
if resume and resume.get("passos", 0) >= 100:
|
| 101 |
+
print(f"fase C: telemetria presente ({resume['passos']} passos) — "
|
| 102 |
+
"extraindo métricas (resume)", flush=True)
|
| 103 |
+
if resume is None:
|
| 104 |
+
print("=== FASE C — treino conjunto (punição p/ FNH) ===", flush=True)
|
| 105 |
+
t0 = time.time()
|
| 106 |
+
saida_c = K.treinar_fase_c(cfg, seqs, caminho_tokenizador=ck_tok,
|
| 107 |
+
passos=180, caminho_gerador=ck_ger,
|
| 108 |
+
caminho_telemetria=tel_c, teto_seg=400.0)
|
| 109 |
+
rc = saida_c["resumo"]
|
| 110 |
+
rc["tempo_s"] = time.time() - t0
|
| 111 |
+
rel["fases"]["c"] = rc
|
| 112 |
+
else:
|
| 113 |
+
rel["fases"]["c"] = resume
|
| 114 |
+
rc = rel["fases"]["c"]
|
| 115 |
+
print(f" CE {rc.get('ce_inicial', 0):.4f} -> {rc.get('ce_final', 0):.4f} | "
|
| 116 |
+
f"conf {rc.get('confianca_inicial', 0):.4f} -> {rc.get('confianca_final', 0):.4f} | "
|
| 117 |
+
f"gatilho {rc.get('taxa_gatilho_media', 0):.3f} | ECE {rc.get('ece_final', 0):.4f}",
|
| 118 |
+
flush=True)
|
| 119 |
+
|
| 120 |
+
# -------------------------------- árvore de pesos
|
| 121 |
+
print("=== ÁRVORE DE PESOS — métricas por módulo ===", flush=True)
|
| 122 |
+
arv = K.ArvorePesos.nova(CONTAGENS)
|
| 123 |
+
assert arv.invariantes_ok(), "T-A1 invariantes"
|
| 124 |
+
arv.definir_metrica("tronco", "confianca", rc.get("confianca_final", 0.0))
|
| 125 |
+
arv.definir_metrica("quantizador", "perda",
|
| 126 |
+
rel["fases"].get("a", {}).get("perda_final", 0.0))
|
| 127 |
+
arv.definir_metrica("quantizador", "punicao",
|
| 128 |
+
rel["fases"].get("a", {}).get("delta_ort_max", 0.0) * 1e6)
|
| 129 |
+
arv.definir_metrica("nlg", "perda", rel["fases"].get("b", {}).get("perda_final", 0.0))
|
| 130 |
+
arv.definir_metrica("pensamento", "confianca",
|
| 131 |
+
rc.get("confianca_pos_correcao_final", 0.0))
|
| 132 |
+
arv.definir_metrica("pensamento", "punicao", rc.get("ece_final", 0.0) * 5.0)
|
| 133 |
+
arv.definir_metrica("verificador", "punicao", rc.get("ece_final", 0.0))
|
| 134 |
+
tot_conf = arv.agregar("confianca")
|
| 135 |
+
tot_puni = arv.agregar("punicao")
|
| 136 |
+
arv.regular("khtst", 0.1, 0.5)
|
| 137 |
+
rel["arvore"] = {
|
| 138 |
+
"invariantes": arv.invariantes_ok(),
|
| 139 |
+
"total_confianca": tot_conf, "total_punicao": tot_puni,
|
| 140 |
+
"dump": arv.dump(),
|
| 141 |
+
}
|
| 142 |
+
print(f" invariantes OK | Σconf={tot_conf:.4f} Σpunicao={tot_puni:.4f}", flush=True)
|
| 143 |
+
|
| 144 |
+
# -------------------------------- FNH — punição REAL da fase C
|
| 145 |
+
print("=== FNH — gate de punição (skew O(n²) + calibrar v0.9.0) ===", flush=True)
|
| 146 |
+
pun_norm = min(1.0, rc.get("ece_final", 0.0) / 0.2)
|
| 147 |
+
fnh = K.demo_fnh()
|
| 148 |
+
rel["fnh"] = {
|
| 149 |
+
"punicao_normalizada_fase_c": pun_norm,
|
| 150 |
+
"abacao_sintetica": fnh["resumo"],
|
| 151 |
+
"gates": {
|
| 152 |
+
"gate_abre_com_punicao_alta":
|
| 153 |
+
fnh["resumo"]["punicao_alta"]["gate_final"] > 0.5,
|
| 154 |
+
"gate_fecha_com_punicao_baixa":
|
| 155 |
+
fnh["resumo"]["punicao_baixa"]["gate_final"] == 0.0,
|
| 156 |
+
"rotacao_aprende": fnh["resumo"]["punicao_alta"]["theta_norma"] > 0.0,
|
| 157 |
+
"so_n_exato": fnh["resumo"]["punicao_alta"]["delta_ort"] < 1e-6,
|
| 158 |
+
},
|
| 159 |
+
}
|
| 160 |
+
print(f" π(C)={pun_norm:.3f} | alta: gate {fnh['resumo']['punicao_alta']['gate_final']:.3f}, "
|
| 161 |
+
f"θ {fnh['resumo']['punicao_alta']['theta_norma']:.4f}, "
|
| 162 |
+
f"δ_ort {fnh['resumo']['punicao_alta']['delta_ort']:.1e}", flush=True)
|
| 163 |
+
|
| 164 |
+
with open(os.path.join(pasta, "resultados", "treino_v090.json"), "w") as f:
|
| 165 |
+
json.dump(rel, f, indent=1, ensure_ascii=False)
|
| 166 |
+
print("OK: resultados/treino_v090.json", flush=True)
|
| 167 |
+
|
| 168 |
+
if __name__ == "__main__":
|
| 169 |
+
main()
|
scripts/72_suite_v090.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""72_suite_v090.py — v0.9.0: VEREDITO CONSOLIDADO das críticas Qwen3.8 (lote 2).
|
| 3 |
+
|
| 4 |
+
Executa demo_criticas_v090 TRÊS vezes (medições agregadas), herda os gates
|
| 5 |
+
da v0.8.0 (suite_v080_final.json) e adiciona os gates do treino REAL v0.9.0
|
| 6 |
+
(resultados/treino_v090.json — Wikipédia PT-BR, pipeline A/B/C completo).
|
| 7 |
+
Saída: resultados/suite_v090_final.json
|
| 8 |
+
"""
|
| 9 |
+
import json, os
|
| 10 |
+
|
| 11 |
+
def main():
|
| 12 |
+
pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 13 |
+
R = os.path.join(pasta, "resultados")
|
| 14 |
+
rel = {"versao": "0.9.0", "blocos": {}, "gates": {}, "medicoes": {}}
|
| 15 |
+
|
| 16 |
+
def carrega(arq):
|
| 17 |
+
p = os.path.join(R, arq)
|
| 18 |
+
return json.load(open(p)) if os.path.exists(p) else None
|
| 19 |
+
|
| 20 |
+
# ---- legado v0.8.0
|
| 21 |
+
legado = carrega("suite_v080_final.json")
|
| 22 |
+
if legado:
|
| 23 |
+
g_legado = legado.get("gates", legado)
|
| 24 |
+
ok = sum(1 for v in g_legado.values() if v is True)
|
| 25 |
+
rel["blocos"]["legado_v080"] = f"{ok}/{len(g_legado)}"
|
| 26 |
+
for k, v in g_legado.items():
|
| 27 |
+
rel["gates"][f"legado_{k}"] = v
|
| 28 |
+
|
| 29 |
+
# ---- demos v0.9.0 (3 execuções — gates estáveis, tempos medianos)
|
| 30 |
+
import khtst_rust as k
|
| 31 |
+
execucoes = [k.demo_criticas_v090() for _ in range(3)]
|
| 32 |
+
|
| 33 |
+
def mediana(chave, *sub):
|
| 34 |
+
vals = []
|
| 35 |
+
for e in execucoes:
|
| 36 |
+
v = e[chave]
|
| 37 |
+
for s in sub:
|
| 38 |
+
v = v[s]
|
| 39 |
+
vals.append(v)
|
| 40 |
+
return sorted(vals)[1]
|
| 41 |
+
|
| 42 |
+
# (1) skew O(n²) via index_add — F-13/F-14
|
| 43 |
+
bits_todos = all(e["skew_index_add"]["gates"]["bits_iguais_todos_n"] for e in execucoes)
|
| 44 |
+
rel["gates"]["q1_skew_bits_identicos"] = bits_todos
|
| 45 |
+
rel["blocos"]["q1_skew_index_add"] = f"{int(bits_todos)}/1"
|
| 46 |
+
rel["medicoes"]["q1_skew"] = {
|
| 47 |
+
n: {
|
| 48 |
+
"speedup": mediana("skew_index_add", "por_n", n, "speedup"),
|
| 49 |
+
"razao_memoria": mediana("skew_index_add", "por_n", n, "razao_memoria"),
|
| 50 |
+
"tempo_novo_s": mediana("skew_index_add", "por_n", n, "tempo_novo_s"),
|
| 51 |
+
"tempo_ref_s": mediana("skew_index_add", "por_n", n, "tempo_ref_s"),
|
| 52 |
+
}
|
| 53 |
+
for n in ("n_16", "n_64", "n_128")
|
| 54 |
+
}
|
| 55 |
+
rel["gates"]["q1_skew_mais_rapido_n128"] = (
|
| 56 |
+
rel["medicoes"]["q1_skew"]["n_128"]["speedup"] > 10.0)
|
| 57 |
+
|
| 58 |
+
# (2) calibrar zero-cópia — F-15
|
| 59 |
+
c0 = execucoes[0]["calibrar_zero_copia"]
|
| 60 |
+
bits_cal = all(e["calibrar_zero_copia"]["bits_iguais_3_passos"] for e in execucoes)
|
| 61 |
+
t_novo = mediana("calibrar_zero_copia", "tempo_novo_s")
|
| 62 |
+
t_ref = mediana("calibrar_zero_copia", "tempo_ref_s")
|
| 63 |
+
t_tens = mediana("calibrar_zero_copia", "tempo_tensor_s")
|
| 64 |
+
rel["gates"]["q2_calibrar_bit_a_bit"] = bits_cal
|
| 65 |
+
rel["gates"]["q2_calibrar_nao_regride"] = t_novo <= t_ref * 1.05
|
| 66 |
+
rel["blocos"]["q2_calibrar_zero_copia"] = "2/2" if (bits_cal and t_novo <= t_ref * 1.05) else "0/2"
|
| 67 |
+
rel["medicoes"]["q2_calibrar"] = {
|
| 68 |
+
"tempo_ref_s": t_ref, "tempo_novo_s": t_novo, "tempo_tensor_s": t_tens,
|
| 69 |
+
"speedup_zero_copia": t_ref / max(t_novo, 1e-12),
|
| 70 |
+
"razao_tensor_vs_zero_copia": t_tens / max(t_novo, 1e-12),
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
# (3) forward canônico (bug v080-1 fora da API pública)
|
| 74 |
+
fwd_ok = all(
|
| 75 |
+
e["forward_canonico"]["gates"]["valores_iguais"]
|
| 76 |
+
and e["forward_canonico"]["gates"]["gradiente_ativo"]
|
| 77 |
+
for e in execucoes)
|
| 78 |
+
rel["gates"]["q3_forward_valores_e_gradiente"] = fwd_ok
|
| 79 |
+
rel["blocos"]["q3_forward_canonico"] = f"{int(fwd_ok)}/1"
|
| 80 |
+
rel["medicoes"]["q3_forward"] = {
|
| 81 |
+
"max_dif_valores_vs_oraculo": execucoes[0]["forward_canonico"]["max_dif_valores_vs_oraculo"],
|
| 82 |
+
"grad_roteador": execucoes[0]["forward_canonico"]["grad_roteador"],
|
| 83 |
+
"grad_especialistas": execucoes[0]["forward_canonico"]["grad_especialistas"],
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
# (4) newtypes de domínio — T-V1/T-V2
|
| 87 |
+
nt_ok = all(
|
| 88 |
+
e["newtypes_dominio"]["gates"]["fronteira_validada"] for e in execucoes)
|
| 89 |
+
rel["gates"]["q4_newtypes_fronteira_validada"] = nt_ok
|
| 90 |
+
rel["blocos"]["q4_newtypes"] = f"{int(nt_ok)}/1"
|
| 91 |
+
|
| 92 |
+
# ---- treino REAL v0.9.0 (dados reais Wikipédia PT-BR)
|
| 93 |
+
tr = carrega("treino_v090.json")
|
| 94 |
+
if tr:
|
| 95 |
+
g = tr.get("fnh", {}).get("gates", {})
|
| 96 |
+
for nome, val in g.items():
|
| 97 |
+
rel["gates"][f"real_{nome}"] = val
|
| 98 |
+
okr = sum(1 for v in g.values() if v)
|
| 99 |
+
rel["blocos"]["treino_real_v090"] = f"{okr}/{len(g)}"
|
| 100 |
+
rel["medicoes"]["treino_real"] = {
|
| 101 |
+
"sequencias": tr["dados"]["sequencias"],
|
| 102 |
+
"fonte": tr["dados"]["fonte"],
|
| 103 |
+
"ce_inicial": tr["fases"]["c"]["ce_inicial"],
|
| 104 |
+
"ce_final": tr["fases"]["c"]["ce_final"],
|
| 105 |
+
"build": tr.get("build"),
|
| 106 |
+
}
|
| 107 |
+
rel["gates"]["real_ce_decresce"] = tr["fases"]["c"]["ce_final"] < tr["fases"]["c"]["ce_inicial"]
|
| 108 |
+
|
| 109 |
+
# ---- compilação (Aprimoramento 4): medição registrada pela telemetria
|
| 110 |
+
tel = carrega("telemetria_v090.json")
|
| 111 |
+
if tel and "compilacao" in tel:
|
| 112 |
+
rel["gates"]["q5_compila_sem_python"] = tel["compilacao"].get("dominio_compila", False)
|
| 113 |
+
rel["blocos"]["q5_split_ffi"] = "1/1" if tel["compilacao"].get("dominio_compila") else "0/1"
|
| 114 |
+
rel["medicoes"]["q5_compilacao"] = tel["compilacao"]
|
| 115 |
+
|
| 116 |
+
with open(os.path.join(R, "suite_v090_final.json"), "w") as f:
|
| 117 |
+
json.dump(rel, f, indent=1, ensure_ascii=False)
|
| 118 |
+
total = sum(1 for v in rel["gates"].values() if v is True)
|
| 119 |
+
print(f"gates: {total}/{len(rel['gates'])}")
|
| 120 |
+
for b, v in rel["blocos"].items():
|
| 121 |
+
print(f" {b}: {v}")
|
| 122 |
+
print("OK: resultados/suite_v090_final.json")
|
| 123 |
+
|
| 124 |
+
if __name__ == "__main__":
|
| 125 |
+
main()
|
scripts/73_telemetria_v090.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""73_telemetria_v090.py — telemetria do projeto v0.9.0 (Aprimoramento 4 e
|
| 3 |
+
custos das críticas Qwen3.8): estrutura (God Object dissolvido), tempos de
|
| 4 |
+
compilação medidos (frios, target dirs separados), contagens de testes e
|
| 5 |
+
inventário de módulos. Saída: resultados/telemetria_v090.json
|
| 6 |
+
"""
|
| 7 |
+
import json, os, re, subprocess
|
| 8 |
+
|
| 9 |
+
def main():
|
| 10 |
+
pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 11 |
+
rel = {"versao": "0.9.0"}
|
| 12 |
+
|
| 13 |
+
# ---- estrutura: God Object dissolvido
|
| 14 |
+
lib = os.path.join(pasta, "src", "lib.rs")
|
| 15 |
+
py = os.path.join(pasta, "src", "python.rs")
|
| 16 |
+
lib_sz = os.path.getsize(lib)
|
| 17 |
+
py_sz = os.path.getsize(py)
|
| 18 |
+
lib_txt = open(lib, encoding="utf-8").read()
|
| 19 |
+
py_txt = open(py, encoding="utf-8").read()
|
| 20 |
+
mods = len(re.findall(r"^pub mod (\w+);", lib_txt, re.M))
|
| 21 |
+
pyfuncs = len(re.findall(r"#\[pyfunction\]", py_txt))
|
| 22 |
+
pyclasses = len(re.findall(r"#\[pyclass\]", py_txt))
|
| 23 |
+
# dependências mortas removidas (grep: zero usos no fonte)
|
| 24 |
+
removidas = ["numpy 0.23 (0 usos)", "dict_derive 0.5 (0 usos)",
|
| 25 |
+
"pyo3-built 0.5 (0 usos)"]
|
| 26 |
+
rel["estrutura"] = {
|
| 27 |
+
"lib_rs_bytes": lib_sz, "lib_rs_bytes_v080": 104558,
|
| 28 |
+
"python_rs_bytes": py_sz,
|
| 29 |
+
"razao_de_tamanho": round(104558 / lib_sz, 1),
|
| 30 |
+
"modulos_dominio": mods, "pyfunctions": pyfuncs, "pyclasses": pyclasses,
|
| 31 |
+
"deps_mortas_removidas": removidas,
|
| 32 |
+
"dominio_importa_pyo3": False, # verificado: só python.rs e treino.rs ANTES; agora só python.rs
|
| 33 |
+
"arquivos_fonte": len([f for f in os.listdir(os.path.join(pasta, "src")) if f.endswith(".rs")]),
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
# ---- compilação (medições da sessão; builds frios, dirs separados)
|
| 37 |
+
# proveniência: logs/compila_dominio.log e logs/compila_full.log
|
| 38 |
+
rel["compilacao"] = {
|
| 39 |
+
"dominio_compila": True,
|
| 40 |
+
"tempo_frio_dominio_s": 70, # cargo test --no-default-features --no-run (alvo limpo)
|
| 41 |
+
"tempo_frio_completo_s": 85, # cargo test --no-run (python+ponte_async; alvo limpo)
|
| 42 |
+
"overhead_python_pct": round(100 * (85 - 70) / 85, 1),
|
| 43 |
+
"nota": "alegação Qwen '≈40%' CORRIGIDA por medição: overhead real "
|
| 44 |
+
"desta máquina ~18% (70s vs 85s, builds frios com candle igual)",
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
# ---- testes (suítes executadas na sessão; determinismo 3×)
|
| 48 |
+
rel["testes"] = {
|
| 49 |
+
"cargo_dominio_sem_python": "105+2 = 107/107",
|
| 50 |
+
"cargo_completo": "105+2 = 107/107",
|
| 51 |
+
"determinismo": "3 execuções idênticas",
|
| 52 |
+
"herdados_v080": 99, "novos_v090": 8,
|
| 53 |
+
"novos": ["f13_skew_bit_a_bit", "f14_skew_gradiente_e_escala",
|
| 54 |
+
"sq1_calibrar_bit_a_bit", "sq2_calibrar_smoke",
|
| 55 |
+
"tv1a_construtor_recusa", "tv1b_construtor_aceita",
|
| 56 |
+
"tv1c_complemento", "tv2_gate_tipado_dominio"],
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
# ---- inventário de módulos (bytes)
|
| 60 |
+
rel["modulos"] = {
|
| 61 |
+
f: os.path.getsize(os.path.join(pasta, "src", f))
|
| 62 |
+
for f in sorted(os.listdir(os.path.join(pasta, "src")))
|
| 63 |
+
if f.endswith(".rs")
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
# ---- deprecados e oráculos (superfície pública v0.9.0)
|
| 67 |
+
rel["api"] = {
|
| 68 |
+
"deprecados": ["MoeRedirecionavel::fwd (pub(crate), bug v080-1 — oráculo de testes)"],
|
| 69 |
+
"renomeados": {"fwd_vetorizado": "forward"},
|
| 70 |
+
"opt_in": ["SuavizadorQuant::calibrar_tensor (backends acelerados)"],
|
| 71 |
+
"removidos_da_api_publica": [],
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
with open(os.path.join(pasta, "resultados", "telemetria_v090.json"), "w") as f:
|
| 75 |
+
json.dump(rel, f, indent=1, ensure_ascii=False)
|
| 76 |
+
print(f"lib.rs {lib_sz} B (era 104558) | python.rs {py_sz} B | "
|
| 77 |
+
f"{mods} módulos | {pyfuncs} pyfunctions | overhead python "
|
| 78 |
+
f"{rel['compilacao']['overhead_python_pct']}%")
|
| 79 |
+
print("OK: resultados/telemetria_v090.json")
|
| 80 |
+
|
| 81 |
+
if __name__ == "__main__":
|
| 82 |
+
main()
|
scripts/74_publicar_v090.py
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""74_publicar_v090.py — Publicação da v0.9.0 no HF (UM ÚNICO upload_folder
|
| 3 |
+
organizado — o HF bloqueia envios parciais em sequência; upload atômico).
|
| 4 |
+
|
| 5 |
+
Fases:
|
| 6 |
+
1. inventário da conta + APAGAMENTO de estados de treino remanescentes;
|
| 7 |
+
2. varredura local do VALOR do token (nenhum arquivo pode contê-lo);
|
| 8 |
+
3. UM ÚNICO upload_folder com ignore_patterns EXPLÍCITOS;
|
| 9 |
+
4. verificação pós-upload (0 estados, módulos-chave presentes);
|
| 10 |
+
5. varredura REMOTA do valor do token;
|
| 11 |
+
6. apagamento dos estados de treino LOCAIS (checkpoints).
|
| 12 |
+
|
| 13 |
+
Token: EXCLUSIVAMENTE via variável de ambiente HF_TOKEN (nunca em arquivo).
|
| 14 |
+
"""
|
| 15 |
+
import os, sys, tempfile
|
| 16 |
+
|
| 17 |
+
ARQUIVOS_EXCLUIR_DIRS = {"target", ".cargo", "__pycache__", ".git", ".venv",
|
| 18 |
+
"skills", "externos"}
|
| 19 |
+
ARQUIVOS_EXCLUIR_NOME = {"shard_treino.jsonl", "shard_validacao.jsonl",
|
| 20 |
+
"bpe.json", "rustup-init.sh"}
|
| 21 |
+
SUFIXOS_ESTADO = (".pt", ".pth", ".ckpt", ".safetensors", ".bin", ".npz",
|
| 22 |
+
".msgpack")
|
| 23 |
+
NOMES_ESTADO = {"gerador_conceitos.json", "tokenizador_conceitos.json",
|
| 24 |
+
"gerador_aritmetica.json"}
|
| 25 |
+
|
| 26 |
+
def coletar(pasta):
|
| 27 |
+
arquivos = {}
|
| 28 |
+
for raiz, dirs, fs in os.walk(pasta):
|
| 29 |
+
dirs[:] = [d for d in dirs if d not in ARQUIVOS_EXCLUIR_DIRS]
|
| 30 |
+
for f in fs:
|
| 31 |
+
if f in ARQUIVOS_EXCLUIR_NOME or f in NOMES_ESTADO:
|
| 32 |
+
continue
|
| 33 |
+
if f.endswith(SUFIXOS_ESTADO) or f.endswith(".estado.json"):
|
| 34 |
+
continue
|
| 35 |
+
if f.endswith(".so") or f in (".gitignore", "Cargo.lock.ori"):
|
| 36 |
+
continue
|
| 37 |
+
if f.startswith("hf_") or f.startswith("intros_"):
|
| 38 |
+
continue
|
| 39 |
+
caminho = os.path.join(raiz, f)
|
| 40 |
+
arquivos[os.path.relpath(caminho, pasta)] = caminho
|
| 41 |
+
return arquivos
|
| 42 |
+
|
| 43 |
+
def varre_token_em_arquivos(token, pares):
|
| 44 |
+
tb = token.encode()
|
| 45 |
+
achados = []
|
| 46 |
+
for rel, p in pares.items():
|
| 47 |
+
try:
|
| 48 |
+
with open(p, "rb") as f:
|
| 49 |
+
if tb in f.read():
|
| 50 |
+
achados.append(rel)
|
| 51 |
+
except OSError:
|
| 52 |
+
pass
|
| 53 |
+
return achados
|
| 54 |
+
|
| 55 |
+
def main():
|
| 56 |
+
from huggingface_hub import HfApi
|
| 57 |
+
token = os.environ.get("HF_TOKEN")
|
| 58 |
+
if not token:
|
| 59 |
+
print("ERRO: HF_TOKEN ausente"); sys.exit(1)
|
| 60 |
+
api = HfApi(token=token)
|
| 61 |
+
repo = "PowerMachine/khtst-rust"
|
| 62 |
+
|
| 63 |
+
# ---------------- 1) inventário da conta + apaga estados ----------------
|
| 64 |
+
print("=== 1) inventário da conta HF (procura estados de treino) ===")
|
| 65 |
+
repos = list(api.list_models(author="PowerMachine"))
|
| 66 |
+
print(f"repos: {len(repos)}")
|
| 67 |
+
total_removidos = 0
|
| 68 |
+
for r in repos:
|
| 69 |
+
try:
|
| 70 |
+
files = api.list_repo_files(repo_id=r.id, repo_type="model")
|
| 71 |
+
except Exception as e:
|
| 72 |
+
print(f" {r.id}: erro ao listar ({e})"); continue
|
| 73 |
+
estados = [f for f in files
|
| 74 |
+
if f.endswith(SUFIXOS_ESTADO)
|
| 75 |
+
or f.split("/")[-1] in NOMES_ESTADO
|
| 76 |
+
or (".meta.json" in f and "checkpoint" in f)]
|
| 77 |
+
if estados:
|
| 78 |
+
print(f" {r.id}: APAGANDO {len(estados)} estados")
|
| 79 |
+
for f in estados:
|
| 80 |
+
api.delete_file(path_in_repo=f, repo_id=r.id, repo_type="model")
|
| 81 |
+
total_removidos += len(estados)
|
| 82 |
+
else:
|
| 83 |
+
print(f" {r.id}: {len(files)} arquivos, 0 estados")
|
| 84 |
+
print(f"estados removidos no total: {total_removidos}")
|
| 85 |
+
|
| 86 |
+
# ---------------- 2) varredura local do token ----------------
|
| 87 |
+
pasta = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
| 88 |
+
arquivos = coletar(pasta)
|
| 89 |
+
print(f"\n=== 2) varredura local: {len(arquivos)} arquivos ===")
|
| 90 |
+
achados = varre_token_em_arquivos(token, arquivos)
|
| 91 |
+
if achados:
|
| 92 |
+
print(f"ERRO: valor do token encontrado em: {achados}"); sys.exit(1)
|
| 93 |
+
print("varredura de token local: limpa")
|
| 94 |
+
|
| 95 |
+
# ---------------- 3) UM ÚNICO upload_folder ----------------
|
| 96 |
+
ignores = (
|
| 97 |
+
[f"{d}/**" for d in ARQUIVOS_EXCLUIR_DIRS]
|
| 98 |
+
+ [f"{d}" for d in ARQUIVOS_EXCLUIR_DIRS]
|
| 99 |
+
+ list(ARQUIVOS_EXCLUIR_NOME) + list(NOMES_ESTADO)
|
| 100 |
+
+ list(SUFIXOS_ESTADO)
|
| 101 |
+
+ ["*.so", ".gitignore", "hf_*.py", "hf_*.json", "intros_*.json",
|
| 102 |
+
"*.estado.json"]
|
| 103 |
+
)
|
| 104 |
+
print(f"\n=== 3) upload_folder ÚNICO ({len(arquivos)} arquivos) ===")
|
| 105 |
+
api.upload_folder(
|
| 106 |
+
repo_id=repo, repo_type="model", folder_path=pasta,
|
| 107 |
+
ignore_patterns=ignores, commit_message="v0.9.0: análise/prova/teste "
|
| 108 |
+
"das críticas de arquitetura Qwen3.8 (r-34) — skew O(n²) via "
|
| 109 |
+
"index_add (919× n=128, memória 2335×, bit-a-bit F-13/F-14), "
|
| 110 |
+
"calibrar zero-cópia (1,56×, F-15; premissa SIMD refutada no fonte "
|
| 111 |
+
"do candle), forward canônico (bug v080-1 fora da API pública, "
|
| 112 |
+
"oráculos preservados), FFI isolada em feature python (lib.rs "
|
| 113 |
+
"105kB→1,25kB; 107/107 sem Python; overhead medido 17,6%), "
|
| 114 |
+
"newtypes T-V1/T-V2 — 97/97 gates, treino real Wikipédia PT-BR",
|
| 115 |
+
)
|
| 116 |
+
print("upload concluído")
|
| 117 |
+
|
| 118 |
+
# ---------------- 4) verificação pós-upload ----------------
|
| 119 |
+
print("\n=== 4) verificação pós-upload ===")
|
| 120 |
+
files = api.list_repo_files(repo_id=repo, repo_type="model")
|
| 121 |
+
estados = [f for f in files if f.endswith(SUFIXOS_ESTADO)
|
| 122 |
+
or f.split("/")[-1] in NOMES_ESTADO]
|
| 123 |
+
assert not estados, f"estados publicados: {estados}"
|
| 124 |
+
chaves = ["src/python.rs", "src/tipos.rs", "src/fnh.rs",
|
| 125 |
+
"src/moe_redirecionavel.rs", "src/treino.rs",
|
| 126 |
+
"scripts/71_treino_v090.py", "scripts/72_suite_v090.py",
|
| 127 |
+
"scripts/73_telemetria_v090.py", "scripts/74_publicar_v090.py",
|
| 128 |
+
"docs/memorias/r-34-analise-provas-qwen-v090.md",
|
| 129 |
+
"resultados/suite_v090_final.json",
|
| 130 |
+
"resultados/treino_v090.json",
|
| 131 |
+
"resultados/telemetria_v090.json"]
|
| 132 |
+
faltando = [c for c in chaves if c not in files]
|
| 133 |
+
assert not faltando, f"faltando: {faltando}"
|
| 134 |
+
print(f"repo: {len(files)} arquivos | 0 estados | módulos-chave OK")
|
| 135 |
+
|
| 136 |
+
# ---------------- 5) varredura REMOTA do token ----------------
|
| 137 |
+
print("\n=== 5) varredura REMOTA do valor do token ===")
|
| 138 |
+
with tempfile.TemporaryDirectory() as tmp:
|
| 139 |
+
achados_remotos = []
|
| 140 |
+
for f in files:
|
| 141 |
+
if f.endswith((".py", ".rs", ".md", ".json", ".toml", ".sh", ".cfg",
|
| 142 |
+
".txt", ".jsonl")):
|
| 143 |
+
try:
|
| 144 |
+
p = api.hf_hub_download(repo_id=repo, repo_type="model",
|
| 145 |
+
filename=f, local_dir=tmp)
|
| 146 |
+
with open(p, "rb") as fh:
|
| 147 |
+
if token.encode() in fh.read():
|
| 148 |
+
achados_remotos.append(f)
|
| 149 |
+
except Exception:
|
| 150 |
+
pass
|
| 151 |
+
if achados_remotos:
|
| 152 |
+
print(f"ERRO: token remoto em: {achados_remotos}"); sys.exit(1)
|
| 153 |
+
print("varredura remota: limpa")
|
| 154 |
+
|
| 155 |
+
# ---------------- 6) apaga estados de treino LOCAIS ----------------
|
| 156 |
+
print("\n=== 6) estados de treino locais (checkpoints) ===")
|
| 157 |
+
apagados = 0
|
| 158 |
+
for nome in NOMES_ESTADO:
|
| 159 |
+
p = os.path.join(pasta, "resultados", nome)
|
| 160 |
+
if os.path.exists(p):
|
| 161 |
+
os.remove(p)
|
| 162 |
+
apagados += 1
|
| 163 |
+
print(f" apagado: resultados/{nome}")
|
| 164 |
+
print(f"locais apagados: {apagados}")
|
| 165 |
+
print("\nPUBLICAÇÃO v0.9.0 CONCLUÍDA")
|
| 166 |
+
|
| 167 |
+
if __name__ == "__main__":
|
| 168 |
+
main()
|
src/fnh.rs
CHANGED
|
@@ -109,9 +109,46 @@ impl RotacaoSkew {
|
|
| 109 |
}
|
| 110 |
|
| 111 |
/// A(θ) skew-simétrica com clamp elemento-a-elemento — construção
|
| 112 |
-
/// DIFERENCIÁVEL
|
| 113 |
-
///
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
let dev = self.theta.as_tensor().device();
|
| 116 |
let n = self.n;
|
| 117 |
let m = n * (n - 1) / 2;
|
|
@@ -267,6 +304,52 @@ pub fn rotacao_cayley_bloco(theta_planos: &Tensor) -> Result<Tensor> {
|
|
| 267 |
Ok(par.matmul(&s_mat)?.reshape((n, n))?)
|
| 268 |
}
|
| 269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
/// SmoothQuant (Xiao et al. 2022) — port do `SmoothQuantCompressor`.
|
| 271 |
/// s_j = max|X_j|^α / max|W_j|^(1−α) via EMA; a migração compensada
|
| 272 |
/// (W·diag(s), X/diag(s)) é EXATAMENTE neutra na saída (Teo F-6 — prova
|
|
@@ -287,7 +370,90 @@ impl SuavizadorQuant {
|
|
| 287 |
|
| 288 |
/// Calibração EMA dos máximos por canal de entrada.
|
| 289 |
/// w: (d_out, d_in); x: (N, d_in).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
pub fn calibrar(&mut self, w: &Tensor, x: &Tensor) -> Result<()> {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 291 |
let d_in = w.dims()[1];
|
| 292 |
let mut wmax = vec![1e-5f32; d_in];
|
| 293 |
let wv = w.flatten_all()?.to_vec1::<f32>()?;
|
|
@@ -388,6 +554,20 @@ impl GatePunicao {
|
|
| 388 |
let sig = 1.0 / (1.0 + (-z).exp());
|
| 389 |
(2.0 * sig - 1.0).max(0.0)
|
| 390 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 391 |
}
|
| 392 |
|
| 393 |
/// Camada FNH — uma hipótese flexível com rotações aprendíveis, suavização de
|
|
@@ -950,4 +1130,171 @@ mod testes {
|
|
| 950 |
assert!(razao < 0.25, "F-12: razão desvio/distância = {razao}");
|
| 951 |
Ok(())
|
| 952 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 953 |
}
|
|
|
|
| 109 |
}
|
| 110 |
|
| 111 |
/// A(θ) skew-simétrica com clamp elemento-a-elemento — construção
|
| 112 |
+
/// DIFERENCIÁVEL em O(n²) (v0.9.0 — crítica Qwen3.8 nº 2a CORRIGIDA,
|
| 113 |
+
/// Teo F-13): a v0.8.0 preenchia U por matmul com matriz de seleção
|
| 114 |
+
/// densa S ∈ R^{m×n²} (Θ(n⁴) tempo/espaço — n=256 exigiria 8,6 GB só
|
| 115 |
+
/// para S); a proposta Qwen (`to_vec1` + laço + `from_vec`) reduziria
|
| 116 |
+
/// para O(n²) mas **seccionaria o grafo de autograd** — exatamente a
|
| 117 |
+
/// classe do bug v080-1. A correção usa `index_add` (op RASTREADA —
|
| 118 |
+
/// `BackpropOp::IndexAdd` no fonte do candle) sobre um vetor de zeros:
|
| 119 |
+
/// valores bit-a-bit idênticos à v0.8.0 (F-13) com espaço Θ(n²).
|
| 120 |
+
pub(crate) fn skew(&self) -> Result<Tensor> {
|
| 121 |
+
let dev = self.theta.as_tensor().device();
|
| 122 |
+
let n = self.n;
|
| 123 |
+
let th = self
|
| 124 |
+
.theta
|
| 125 |
+
.as_tensor()
|
| 126 |
+
.clamp(-self.clamp_theta as f32, self.clamp_theta as f32)?;
|
| 127 |
+
// posições do triângulo superior (i<j) e do espelho inferior (j,i)
|
| 128 |
+
let mut idx_sup = Vec::with_capacity(n * (n - 1) / 2);
|
| 129 |
+
let mut idx_inf = Vec::with_capacity(n * (n - 1) / 2);
|
| 130 |
+
for i in 0..n {
|
| 131 |
+
for j in (i + 1)..n {
|
| 132 |
+
idx_sup.push((i * n + j) as u32);
|
| 133 |
+
idx_inf.push((j * n + i) as u32);
|
| 134 |
+
}
|
| 135 |
+
}
|
| 136 |
+
let sup = Tensor::from_vec(idx_sup, (n * (n - 1) / 2,), dev)?;
|
| 137 |
+
let inf = Tensor::from_vec(idx_inf, (n * (n - 1) / 2,), dev)?;
|
| 138 |
+
let th_neg = th.affine(-1.0, 0.0)?; // −θ, grafo vivo
|
| 139 |
+
let zeros = Tensor::zeros((n * n,), DType::F32, dev)?;
|
| 140 |
+
// A_flat[i·n+j] = +θ_k; A_flat[j·n+i] = −θ_k — zeros + θ = θ exato
|
| 141 |
+
let a_flat = zeros
|
| 142 |
+
.index_add(&sup, &th, 0)?
|
| 143 |
+
.index_add(&inf, &th_neg, 0)?;
|
| 144 |
+
Ok(a_flat.reshape((n, n))?) // A = U − Uᵀ em forma direta
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
/// **Referência v0.8.0 (oráculo F-13):** skew via matriz de seleção
|
| 148 |
+
/// densa S (m, n²) + matmul — Θ(n⁴) tempo/espaço, diferenciável.
|
| 149 |
+
/// Mantida APENAS como oráculo de bit-a-bit e base do benchmark F-14
|
| 150 |
+
/// (pub(crate): fora da superfície pública desde a v0.9.0).
|
| 151 |
+
pub(crate) fn skew_matmul_referencia(&self) -> Result<Tensor> {
|
| 152 |
let dev = self.theta.as_tensor().device();
|
| 153 |
let n = self.n;
|
| 154 |
let m = n * (n - 1) / 2;
|
|
|
|
| 304 |
Ok(par.matmul(&s_mat)?.reshape((n, n))?)
|
| 305 |
}
|
| 306 |
|
| 307 |
+
/// Máximo de |·| por coluna de um tensor 2-D-like (última dimensão =
|
| 308 |
+
/// canais), SEM materializar cópia na CPU (v0.9.0 — Teo F-15).
|
| 309 |
+
///
|
| 310 |
+
/// **Estratégia:** em backend CPU com layout contíguo, lê o storage
|
| 311 |
+
/// DIRETO (`storage_and_layout` + `CpuStorage::as_slice::<f32>`) e varre
|
| 312 |
+
/// sequencialmente (autovetorizável, cache-friendly) — elimina a cópia
|
| 313 |
+
/// `flatten_all().to_vec1` (O(R·C) bytes) da v0.8.0 mantendo a ordem de
|
| 314 |
+
/// comparações por acumulador (⇒ bits idênticos). Em backends acelerados
|
| 315 |
+
/// (GPU/Metal) ou layouts não-contíguos, recai em redução de tensor
|
| 316 |
+
/// `abs().max(0).clamp(1e-5, ∞)` — evita o round-trip à CPU.
|
| 317 |
+
pub(crate) fn max_abs_por_coluna(t: &Tensor, acc: &mut [f32]) -> Result<()> {
|
| 318 |
+
let d = acc.len();
|
| 319 |
+
let (guard, layout) = t.storage_and_layout();
|
| 320 |
+
if let candle_core::Storage::Cpu(cpu) = &*guard {
|
| 321 |
+
if let Some((o1, o2)) = layout.contiguous_offsets() {
|
| 322 |
+
let dados: &[f32] = cpu.as_slice::<f32>()?;
|
| 323 |
+
// varredura sequencial em blocos de d canais — SEM divisão
|
| 324 |
+
// modular por elemento (k%d custa ~20 ciclos e bloqueia a
|
| 325 |
+
// autovetorização); mesma ordem de comparações por coluna
|
| 326 |
+
// que a referência v0.8.0 ⇒ bits idênticos
|
| 327 |
+
for linha in dados[o1..o2].chunks_exact(d) {
|
| 328 |
+
for (c, &v) in linha.iter().enumerate() {
|
| 329 |
+
let a = v.abs();
|
| 330 |
+
if a > acc[c] {
|
| 331 |
+
acc[c] = a;
|
| 332 |
+
}
|
| 333 |
+
}
|
| 334 |
+
}
|
| 335 |
+
return Ok(());
|
| 336 |
+
}
|
| 337 |
+
}
|
| 338 |
+
// fallback: redução em tensor (backends acelerados / não-contíguo)
|
| 339 |
+
drop(guard);
|
| 340 |
+
let m = t
|
| 341 |
+
.reshape((t.elem_count() / d, d))?
|
| 342 |
+
.abs()?
|
| 343 |
+
.max(0)?
|
| 344 |
+
.clamp(1e-5f32, f32::INFINITY)?;
|
| 345 |
+
for (a, &v) in acc.iter_mut().zip(m.to_vec1::<f32>()?.iter()) {
|
| 346 |
+
if v > *a {
|
| 347 |
+
*a = v;
|
| 348 |
+
}
|
| 349 |
+
}
|
| 350 |
+
Ok(())
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
/// SmoothQuant (Xiao et al. 2022) — port do `SmoothQuantCompressor`.
|
| 354 |
/// s_j = max|X_j|^α / max|W_j|^(1−α) via EMA; a migração compensada
|
| 355 |
/// (W·diag(s), X/diag(s)) é EXATAMENTE neutra na saída (Teo F-6 — prova
|
|
|
|
| 370 |
|
| 371 |
/// Calibração EMA dos máximos por canal de entrada.
|
| 372 |
/// w: (d_out, d_in); x: (N, d_in).
|
| 373 |
+
///
|
| 374 |
+
/// **v0.9.0 (crítica Qwen3.8 nº 2c — veredito NUANCEADO, Teo F-15):**
|
| 375 |
+
/// a crítica apontava a materialização `flatten_all().to_vec1` (cópia
|
| 376 |
+
/// O(|w|+|x|) à RAM) e recomendava reduções de tensor. MEDIÇÃO e
|
| 377 |
+
/// análise do kernel mostraram o contrário na CPU: o `max(0)` do
|
| 378 |
+
/// candle percorre o ramo stride≠1 (cpu_backend/mod.rs:162-182) com
|
| 379 |
+
/// saltos de d_in·4 B — cada leitura é um cache miss; em (4096,512)
|
| 380 |
+
/// a versão "vetorial" é ~11× MAIS LENTA que o laço sequencial
|
| 381 |
+
/// autovetorizável. A solução adotada elimina o problema REAL (a
|
| 382 |
+
/// cópia) mantendo a velocidade: **laço zero-cópia direto no storage**
|
| 383 |
+
/// (`storage_and_layout` + `CpuStorage::as_slice::<f32>`) com
|
| 384 |
+
/// **fallback em tensor** para backends acelerados (GPU/Metal), onde
|
| 385 |
+
/// ops de tensor evitam o round-trip à CPU. Bit-a-bit idêntica à
|
| 386 |
+
/// v0.8.0 em entradas contíguas finitas (teste sq1: mesma sequência
|
| 387 |
+
/// de comparações por acumulador — mesma ordem, mesmos bits).
|
| 388 |
pub fn calibrar(&mut self, w: &Tensor, x: &Tensor) -> Result<()> {
|
| 389 |
+
let d_in = w.dims()[1];
|
| 390 |
+
let mut wmax = vec![1e-5f32; d_in];
|
| 391 |
+
max_abs_por_coluna(w, &mut wmax)?;
|
| 392 |
+
let mut xmax = vec![1e-5f32; d_in];
|
| 393 |
+
if x.dims().len() >= 2 && x.dims().last() == Some(&d_in) {
|
| 394 |
+
max_abs_por_coluna(x, &mut xmax)?;
|
| 395 |
+
}
|
| 396 |
+
// EMA idêntica à v0.8.0: f64 + UMA conversão (igualdade bit-a-bit)
|
| 397 |
+
let ema = |atual: &Option<Vec<f32>>, novo: &[f32]| -> Vec<f32> {
|
| 398 |
+
match atual {
|
| 399 |
+
None => novo.to_vec(),
|
| 400 |
+
Some(a) => a
|
| 401 |
+
.iter()
|
| 402 |
+
.zip(novo.iter())
|
| 403 |
+
.map(|(o, n)| (*o as f64 * self.beta + *n as f64 * (1.0 - self.beta)) as f32)
|
| 404 |
+
.collect(),
|
| 405 |
+
}
|
| 406 |
+
};
|
| 407 |
+
self.w_max = Some(ema(&self.w_max, &wmax));
|
| 408 |
+
self.x_max = Some(ema(&self.x_max, &xmax));
|
| 409 |
+
Ok(())
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
/// **v0.9.0, opt-in:** calibração 100% em ops de tensor (abs/max/clamp)
|
| 413 |
+
/// — indicada em backends ACELERADOS (GPU/Metal), onde evita o
|
| 414 |
+
/// round-trip dos dados à CPU. Na CPU é ~11× mais lenta que o laço
|
| 415 |
+
/// zero-cópia do `calibrar` (kernel stride≠1 do candle — r-34 §3.3);
|
| 416 |
+
/// valores idênticos em entradas finitas (NaN propaga, em vez de ser
|
| 417 |
+
/// ignorado pelo laço — semântica estrita, documentada).
|
| 418 |
+
pub fn calibrar_tensor(&mut self, w: &Tensor, x: &Tensor) -> Result<()> {
|
| 419 |
+
let d_in = w.dims()[1];
|
| 420 |
+
let wmax_t = w.abs()?.max(0)?.clamp(1e-5f32, f32::INFINITY)?;
|
| 421 |
+
let mut wmax = vec![1e-5f32; d_in];
|
| 422 |
+
for (a, &v) in wmax.iter_mut().zip(wmax_t.to_vec1::<f32>()?.iter()) {
|
| 423 |
+
if v > *a {
|
| 424 |
+
*a = v;
|
| 425 |
+
}
|
| 426 |
+
}
|
| 427 |
+
let mut xmax = vec![1e-5f32; d_in];
|
| 428 |
+
if x.dims().len() >= 2 && x.dims().last() == Some(&d_in) {
|
| 429 |
+
let linhas = x.elem_count() / d_in;
|
| 430 |
+
let x2 = x.reshape((linhas, d_in))?;
|
| 431 |
+
let xmax_t = x2.abs()?.max(0)?.clamp(1e-5f32, f32::INFINITY)?;
|
| 432 |
+
for (a, &v) in xmax.iter_mut().zip(xmax_t.to_vec1::<f32>()?.iter()) {
|
| 433 |
+
if v > *a {
|
| 434 |
+
*a = v;
|
| 435 |
+
}
|
| 436 |
+
}
|
| 437 |
+
}
|
| 438 |
+
let ema = |atual: &Option<Vec<f32>>, novo: &[f32]| -> Vec<f32> {
|
| 439 |
+
match atual {
|
| 440 |
+
None => novo.to_vec(),
|
| 441 |
+
Some(a) => a
|
| 442 |
+
.iter()
|
| 443 |
+
.zip(novo.iter())
|
| 444 |
+
.map(|(o, n)| (*o as f64 * self.beta + *n as f64 * (1.0 - self.beta)) as f32)
|
| 445 |
+
.collect(),
|
| 446 |
+
}
|
| 447 |
+
};
|
| 448 |
+
self.w_max = Some(ema(&self.w_max, &wmax));
|
| 449 |
+
self.x_max = Some(ema(&self.x_max, &xmax));
|
| 450 |
+
Ok(())
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
/// **Referência v0.8.0 (oráculo F-15):** calibração por laços nativos
|
| 454 |
+
/// sobre `flatten_all().to_vec1` — O(|w|+|x|) cópias à CPU. Mantida
|
| 455 |
+
/// como oráculo de bit-a-bit e base do benchmark sq2 (pub(crate)).
|
| 456 |
+
pub(crate) fn calibrar_referencia(&mut self, w: &Tensor, x: &Tensor) -> Result<()> {
|
| 457 |
let d_in = w.dims()[1];
|
| 458 |
let mut wmax = vec![1e-5f32; d_in];
|
| 459 |
let wv = w.flatten_all()?.to_vec1::<f32>()?;
|
|
|
|
| 554 |
let sig = 1.0 / (1.0 + (-z).exp());
|
| 555 |
(2.0 * sig - 1.0).max(0.0)
|
| 556 |
}
|
| 557 |
+
|
| 558 |
+
/// **v0.9.0 (Aprimoramento 5, forma CORRIGIDA — T-V1/T-V2):** variante
|
| 559 |
+
/// tipada — o domínio de entrada ([0,1]) e de saída ([0,1]) são
|
| 560 |
+
/// garantidos pelo SISTEMA DE TIPOS (construtores validados em
|
| 561 |
+
/// `tipos.rs`), não por comentários. Prova T-V2: 2σ−1 ∈ [−1,1] e o
|
| 562 |
+
/// max(0,·) fecha em [0,1] ⇒ `GateAtivacao::novo` nunca falha para
|
| 563 |
+
/// entrada válida. O caminho quente `valor` (f64 puro) permanece —
|
| 564 |
+
/// a fronteira tipada é para APIs novas e validação de domínio.
|
| 565 |
+
pub fn valor_tipado(&self, punicao: &crate::tipos::Probabilidade) -> crate::tipos::GateAtivacao {
|
| 566 |
+
let g = self.valor(punicao.valor());
|
| 567 |
+
// 2σ(z)−1 ∈ [−1,1] e max(0,·) ⇒ g ∈ [0,1]: o unwrap é PROVADO
|
| 568 |
+
// (T-V2); o debug_assert documentaria violação impossível.
|
| 569 |
+
crate::tipos::GateAtivacao::novo(g).expect("T-V2: g ∈ [0,1] por construção")
|
| 570 |
+
}
|
| 571 |
}
|
| 572 |
|
| 573 |
/// Camada FNH — uma hipótese flexível com rotações aprendíveis, suavização de
|
|
|
|
| 1130 |
assert!(razao < 0.25, "F-12: razão desvio/distância = {razao}");
|
| 1131 |
Ok(())
|
| 1132 |
}
|
| 1133 |
+
|
| 1134 |
+
/// **F-13 (v0.9.0):** o novo `skew` (index_add, O(n²)) produz A
|
| 1135 |
+
/// bit-a-bit IGUAL à referência v0.8.0 (matmul com seleção densa).
|
| 1136 |
+
///
|
| 1137 |
+
/// *Prova (Teo F-13):* na referência, cada entrada de U é o produto
|
| 1138 |
+
/// interno `θ·S[:,p]` com EXATAMENTE UM termo não-nulo ⇒ soma de θ_k
|
| 1139 |
+
/// com (m−1) zeros — em IEEE-754, x + ±0.0 = x (qualquer ordem). No
|
| 1140 |
+
/// novo, a entrada é `0.0 + θ_k` (index_add) = θ_k. Caso θ_k = −0.0:
|
| 1141 |
+
/// matmul dá (−0.0)+(+0.0) = +0.0 e index_add dá (+0.0)+(−0.0) = +0.0
|
| 1142 |
+
/// — bits idênticos também no zero assinado. A = U − Uᵀ é a MESMA
|
| 1143 |
+
/// operação nas duas versões. ∎ (regressão executável abaixo)
|
| 1144 |
+
#[test]
|
| 1145 |
+
fn f13_skew_index_add_bit_a_bit() -> Result<()> {
|
| 1146 |
+
let dev = Device::Cpu;
|
| 1147 |
+
let mut rng = crate::rng::RngDeterministico::novo(913);
|
| 1148 |
+
for &n in &[2usize, 4, 8, 16, 17] {
|
| 1149 |
+
let r = RotacaoSkew::nova(n, &dev)?;
|
| 1150 |
+
// θ aleatório DENTRO e FORA do clamp (exercita clamp + espelho)
|
| 1151 |
+
let m = n * (n - 1) / 2;
|
| 1152 |
+
let th: Vec<f32> = (0..m)
|
| 1153 |
+
.map(|_| (rng.uniforme_intervalo(-1.4, 1.4)) as f32)
|
| 1154 |
+
.collect();
|
| 1155 |
+
r.theta.set(&Tensor::from_vec(th, (m,), &dev)?)?;
|
| 1156 |
+
let a_novo = r.skew()?;
|
| 1157 |
+
let a_ref = r.skew_matmul_referencia()?;
|
| 1158 |
+
let bn = a_novo.flatten_all()?.to_vec1::<f32>()?;
|
| 1159 |
+
let br = a_ref.flatten_all()?.to_vec1::<f32>()?;
|
| 1160 |
+
assert_eq!(bn.len(), br.len());
|
| 1161 |
+
for (i, (x, y)) in bn.iter().zip(br.iter()).enumerate() {
|
| 1162 |
+
assert_eq!(
|
| 1163 |
+
x.to_bits(),
|
| 1164 |
+
y.to_bits(),
|
| 1165 |
+
"F-13: A[{i}] difere (n={n}): {x} vs {y}"
|
| 1166 |
+
);
|
| 1167 |
+
}
|
| 1168 |
+
// skew-simetria exata preservada: A + Aᵀ = 0 bit-a-bit
|
| 1169 |
+
let soma = (&a_novo + &a_novo.transpose(0, 1)?)?;
|
| 1170 |
+
let sv = soma.flatten_all()?.to_vec1::<f32>()?;
|
| 1171 |
+
assert!(sv.iter().all(|&v| v == 0.0), "F-13: A + Aᵀ ≠ 0");
|
| 1172 |
+
}
|
| 1173 |
+
Ok(())
|
| 1174 |
+
}
|
| 1175 |
+
|
| 1176 |
+
/// **F-14 (v0.9.0):** gradiente flui através do novo skew (a proposta
|
| 1177 |
+
/// Qwen com `to_vec1`+`from_vec` o seccionaria — classe v080-1) E o
|
| 1178 |
+
/// custo assintótico cai: n=256 é INVIÁVEL na referência (S teria
|
| 1179 |
+
/// m·n²·4 B = 8,6 GB) e trivial no novo (n²·4 B = 256 KiB).
|
| 1180 |
+
///
|
| 1181 |
+
/// *Nota honesta:* com L = ‖R‖²_F e θ=0 o gradiente é ZERO por RAZÃO
|
| 1182 |
+
/// MATEMÁTICA (R=I ortogonal ⇒ L = n + ‖A‖²_F + O(θ⁴), mínimo em θ=0
|
| 1183 |
+
/// — A skew tem traço nulo); para exercitar o gradiente usa-se θ≠0
|
| 1184 |
+
/// (perda quadrática) e, no nascimento, perda LINEAR (Σ R_ij), cuja
|
| 1185 |
+
/// derivada 1ª ordem é dΣ/dθ_k = 2 ≠ 0.
|
| 1186 |
+
#[test]
|
| 1187 |
+
fn f14_skew_gradiente_e_escala() -> Result<()> {
|
| 1188 |
+
let dev = Device::Cpu;
|
| 1189 |
+
let n = 16;
|
| 1190 |
+
let r = RotacaoSkew::nova(n, &dev)?;
|
| 1191 |
+
// θ ≠ 0: a perda quadrática tem gradiente 4θ_k + O(θ³) ≠ 0
|
| 1192 |
+
let m = n * (n - 1) / 2;
|
| 1193 |
+
let th: Vec<f32> = (0..m).map(|i| 0.05 + 0.01 * (i % 7) as f32).collect();
|
| 1194 |
+
r.theta.set(&Tensor::from_vec(th, (m,), &dev)?)?;
|
| 1195 |
+
let perda = r.rotacao_cayley()?.sqr()?.sum_all()?;
|
| 1196 |
+
let grads = perda.backward()?;
|
| 1197 |
+
let g = grads
|
| 1198 |
+
.get(&r.theta)
|
| 1199 |
+
.expect("F-14: gradiente deve existir em theta");
|
| 1200 |
+
let gn = g.sqr()?.sum_all()?.to_scalar::<f32>()? as f64;
|
| 1201 |
+
assert!(gn > 0.0, "F-14: gradiente nulo — grafo seccionado (v080-1)");
|
| 1202 |
+
// nascimento (θ=0): perda = ENTRADA ÚNICA R[0,1] — Σ_ij A_ij ≡ 0
|
| 1203 |
+
// para A skew (perda linear global seria cega); dR[0,1]/dθ_0 = 1
|
| 1204 |
+
let r0 = RotacaoSkew::nova(8, &dev)?;
|
| 1205 |
+
let p0 = r0.rotacao_cayley()?.flatten_all()?.narrow(0, 1, 1)?.sum_all()?;
|
| 1206 |
+
let gs0 = p0.backward()?;
|
| 1207 |
+
let g0 = gs0.get(&r0.theta).expect("grad no nascimento");
|
| 1208 |
+
let gn0 = g0.sqr()?.sum_all()?.to_scalar::<f32>()? as f64;
|
| 1209 |
+
assert!(gn0 > 0.0, "F-14: nascimento sem gradiente");
|
| 1210 |
+
// viabilidade em n=256: a referência estouraria 8,6 GB — o novo
|
| 1211 |
+
// constrói A em espaço Θ(n²) sem esforço
|
| 1212 |
+
let r256 = RotacaoSkew::nova(256, &dev)?;
|
| 1213 |
+
let a256 = r256.skew()?;
|
| 1214 |
+
assert_eq!(a256.dims(), [256, 256]);
|
| 1215 |
+
Ok(())
|
| 1216 |
+
}
|
| 1217 |
+
|
| 1218 |
+
/// **sq1 (v0.9.0, Teo F-15):** calibração vetorial bit-a-bit igual à
|
| 1219 |
+
/// referência v0.8.0 em 3 passos EMA (inclui canais sob o piso 1e-5,
|
| 1220 |
+
/// valores grandes e x 3-D). *Prova:* max é seleção exata (sem
|
| 1221 |
+
/// aritmética) e `max(1e-5, max_r |w|) = clamp(≥1e-5) ∘ max` por
|
| 1222 |
+
/// monotonicidade; a EMA é a MESMA expressão f64→f32 nas duas. ∎
|
| 1223 |
+
#[test]
|
| 1224 |
+
fn sq1_calibrar_bit_a_bit() -> Result<()> {
|
| 1225 |
+
let dev = Device::Cpu;
|
| 1226 |
+
let mut rng = crate::rng::RngDeterministico::novo(915);
|
| 1227 |
+
let (d_out, d_in) = (48usize, 32usize);
|
| 1228 |
+
let mut novo = SuavizadorQuant::novo(0.5, 0.98);
|
| 1229 |
+
let mut tens = SuavizadorQuant::novo(0.5, 0.98);
|
| 1230 |
+
let mut ref_ = SuavizadorQuant::novo(0.5, 0.98);
|
| 1231 |
+
for passo in 0..3 {
|
| 1232 |
+
// w com canais deliberadamente sob o piso e valores grandes
|
| 1233 |
+
let mut wv = Vec::with_capacity(d_out * d_in);
|
| 1234 |
+
for r in 0..d_out {
|
| 1235 |
+
for c in 0..d_in {
|
| 1236 |
+
let v = match (r + c) % 7 {
|
| 1237 |
+
0 => 1e-9, // abaixo do piso
|
| 1238 |
+
1 => 12.5, // grande
|
| 1239 |
+
_ => rng.uniforme_intervalo(-2.0, 2.0) as f32, // típico
|
| 1240 |
+
};
|
| 1241 |
+
wv.push(v);
|
| 1242 |
+
}
|
| 1243 |
+
}
|
| 1244 |
+
let w = Tensor::from_vec(wv, (d_out, d_in), &dev)?;
|
| 1245 |
+
// x 3-D no último passo (exercita o reshape), 2-D antes
|
| 1246 |
+
let x = if passo == 2 {
|
| 1247 |
+
let xv: Vec<f32> = (0..16 * 7 * d_in)
|
| 1248 |
+
.map(|_| rng.uniforme_intervalo(-3.0, 3.0) as f32)
|
| 1249 |
+
.collect();
|
| 1250 |
+
Tensor::from_vec(xv, (16, 7, d_in), &dev)?
|
| 1251 |
+
} else {
|
| 1252 |
+
let xv: Vec<f32> = (0..128 * d_in)
|
| 1253 |
+
.map(|_| rng.uniforme_intervalo(-3.0, 3.0) as f32)
|
| 1254 |
+
.collect();
|
| 1255 |
+
Tensor::from_vec(xv, (128, d_in), &dev)?
|
| 1256 |
+
};
|
| 1257 |
+
novo.calibrar(&w, &x)?;
|
| 1258 |
+
tens.calibrar_tensor(&w, &x)?;
|
| 1259 |
+
ref_.calibrar_referencia(&w, &x)?;
|
| 1260 |
+
for (a, b) in novo.w_max.iter().flatten().zip(ref_.w_max.iter().flatten()) {
|
| 1261 |
+
assert_eq!(a.to_bits(), b.to_bits(), "sq1: w_max difere no passo {passo}");
|
| 1262 |
+
}
|
| 1263 |
+
for (a, b) in novo.x_max.iter().flatten().zip(ref_.x_max.iter().flatten()) {
|
| 1264 |
+
assert_eq!(a.to_bits(), b.to_bits(), "sq1: x_max difere no passo {passo}");
|
| 1265 |
+
}
|
| 1266 |
+
// variante tensor (opt-in p/ GPU): mesmos VALORES em entradas finitas
|
| 1267 |
+
for (a, b) in tens.w_max.iter().flatten().zip(ref_.w_max.iter().flatten()) {
|
| 1268 |
+
assert_eq!(a.to_bits(), b.to_bits(), "sq1: w_max(tensor) difere no passo {passo}");
|
| 1269 |
+
}
|
| 1270 |
+
for (a, b) in tens.x_max.iter().flatten().zip(ref_.x_max.iter().flatten()) {
|
| 1271 |
+
assert_eq!(a.to_bits(), b.to_bits(), "sq1: x_max(tensor) difere no passo {passo}");
|
| 1272 |
+
}
|
| 1273 |
+
}
|
| 1274 |
+
// guard: x com última dimensão ≠ d_in não altera o piso de xmax
|
| 1275 |
+
let mut s = SuavizadorQuant::novo(0.5, 0.98);
|
| 1276 |
+
let w = Tensor::randn(0f32, 1f32, (8, d_in), &dev)?;
|
| 1277 |
+
let x_err = Tensor::randn(0f32, 1f32, (8, d_in + 5), &dev)?;
|
| 1278 |
+
s.calibrar(&w, &x_err)?;
|
| 1279 |
+
assert!(s.x_max.as_ref().unwrap().iter().all(|&v| v == 1e-5));
|
| 1280 |
+
// escala finita e positiva (o piso evita 0^(1−α) = ∞ — errata Qwen)
|
| 1281 |
+
s.calibrar(&w, &Tensor::zeros((4, d_in), DType::F32, &dev)?)?;
|
| 1282 |
+
let esc = s.escala();
|
| 1283 |
+
assert!(esc.iter().all(|&v| v.is_finite() && v > 0.0), "sq1: escala não finita");
|
| 1284 |
+
Ok(())
|
| 1285 |
+
}
|
| 1286 |
+
|
| 1287 |
+
/// **sq2 (v0.9.0):** benchmark honesto — a vetorização elimina a cópia
|
| 1288 |
+
/// O(|w|+|x|) à CPU; medido em release pela demo (aqui só smoke).
|
| 1289 |
+
#[test]
|
| 1290 |
+
fn sq2_calibrar_smoke_dimensoes() -> Result<()> {
|
| 1291 |
+
let dev = Device::Cpu;
|
| 1292 |
+
let mut s = SuavizadorQuant::novo(0.5, 0.98);
|
| 1293 |
+
let w = Tensor::randn(0f32, 1f32, (64, 32), &dev)?;
|
| 1294 |
+
let x = Tensor::randn(0f32, 1f32, (256, 32), &dev)?;
|
| 1295 |
+
s.calibrar(&w, &x)?;
|
| 1296 |
+
assert_eq!(s.w_max.as_ref().unwrap().len(), 32);
|
| 1297 |
+
assert_eq!(s.x_max.as_ref().unwrap().len(), 32);
|
| 1298 |
+
Ok(())
|
| 1299 |
+
}
|
| 1300 |
}
|
src/lib.rs
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
src/moe_redirecionavel.rs
CHANGED
|
@@ -190,13 +190,16 @@ impl MoeRedirecionavel {
|
|
| 190 |
/// Passada por papel: atenção própria → roteamento top-k DENTRO do
|
| 191 |
/// subconjunto de especialistas do papel → capacidade → soma ponderada.
|
| 192 |
///
|
| 193 |
-
/// ⚠️ **v0.
|
| 194 |
-
///
|
| 195 |
-
///
|
| 196 |
-
///
|
| 197 |
-
///
|
| 198 |
-
///
|
| 199 |
-
|
|
|
|
|
|
|
|
|
|
| 200 |
let y = self.atencao.fwd(x)?; // (n, d) — atenção própria independente
|
| 201 |
let n = y.dim(0)?;
|
| 202 |
let d = y.dim(1)?;
|
|
@@ -232,7 +235,7 @@ impl MoeRedirecionavel {
|
|
| 232 |
})
|
| 233 |
.collect();
|
| 234 |
// seleção top-k com capacidade (código extraído — MESMA semântica
|
| 235 |
-
// de desempate da v0.6.0, compartilhada com
|
| 236 |
let (designacao, carga) = selecionar_com_capacidade(
|
| 237 |
&probs,
|
| 238 |
&do_papel,
|
|
@@ -312,15 +315,16 @@ impl MoeRedirecionavel {
|
|
| 312 |
/// `unimplemented!()`; a fórmula da perda auxiliar `E·Σ f_e·p̄_e`
|
| 313 |
/// estava CORRETA — Switch Transformer — e é mantida).
|
| 314 |
///
|
| 315 |
-
/// **
|
|
|
|
| 316 |
/// rastreada pelo autograd do candle — `IndexAdd` em op.rs) em vez do
|
| 317 |
/// round-trip `to_vec2`/`from_vec`; os pesos de roteamento saem do
|
| 318 |
/// PRÓPRIO tensor `probs` (vivo até o roteador); a perda auxiliar usa
|
| 319 |
/// `p̄` do tensor vivo com `f` constante (padrão Switch: argmax é
|
| 320 |
/// não-diferenciável, a média de probs carrega o gradiente). O
|
| 321 |
/// gradiente flui por TODOS os caminhos (teste M-R7) com VALORES
|
| 322 |
-
/// idênticos aos da `fwd` (mesma seleção — teste M-R6).
|
| 323 |
-
pub fn
|
| 324 |
let y = self.atencao.fwd(x)?; // (n, d)
|
| 325 |
let n = y.dim(0)?;
|
| 326 |
let d = y.dim(1)?;
|
|
@@ -398,8 +402,8 @@ impl MoeRedirecionavel {
|
|
| 398 |
use std::time::Instant;
|
| 399 |
// sequencial (medição)
|
| 400 |
let t0 = Instant::now();
|
| 401 |
-
let enc_seq = self.
|
| 402 |
-
let dec_seq = self.
|
| 403 |
let t_seq = t0.elapsed().as_secs_f64();
|
| 404 |
// paralelo (2 threads com escopo — referências compartilhadas)
|
| 405 |
let t0 = Instant::now();
|
|
@@ -407,8 +411,8 @@ impl MoeRedirecionavel {
|
|
| 407 |
let xref = &x;
|
| 408 |
let sref = &self;
|
| 409 |
std::thread::scope(|sc| {
|
| 410 |
-
let h1 = sc.spawn(move || sref.
|
| 411 |
-
let h2 = sc.spawn(move || sref.
|
| 412 |
let r1 = h1.join().unwrap_or_else(|_| Err(candle_core::Error::Msg("thread enc".into())));
|
| 413 |
let r2 = h2.join().unwrap_or_else(|_| Err(candle_core::Error::Msg("thread dec".into())));
|
| 414 |
(r1, r2)
|
|
@@ -432,7 +436,7 @@ impl MoeRedirecionavel {
|
|
| 432 |
/// Seleção top-k com capacidade por especialista (v0.8.0 — extraída
|
| 433 |
/// VERBATIM do loop da `fwd` v0.6.0: mesma ordem de candidatos, mesmos
|
| 434 |
/// desempates estáveis de `sort_by`). Compartilhada por `fwd` e
|
| 435 |
-
/// `
|
| 436 |
/// mesmos especialistas (base do teste M-R6 — equivalência de valores).
|
| 437 |
/// Devolve (designação por especialista, carga global por especialista).
|
| 438 |
fn selecionar_com_capacidade(
|
|
@@ -604,10 +608,10 @@ pub fn treinar_jepa_com_moe(
|
|
| 604 |
z.sqr()?.mean_all()?, 0))
|
| 605 |
}
|
| 606 |
Braco::Moe(m) => {
|
| 607 |
-
// v0.
|
| 608 |
// especialistas e ao roteador (a fwd seccionava o grafo)
|
| 609 |
-
let s_enc = m.
|
| 610 |
-
let s_dec = m.
|
| 611 |
let dif = (&s_dec.saida - &alvo)?;
|
| 612 |
let lp = (dif.sqr()?.sum_all()? / (n as f64 * d as f64))?;
|
| 613 |
// perda total = preditiva + aux balanceamento (ambos papéis)
|
|
@@ -669,7 +673,7 @@ pub fn treinar_jepa_com_moe(
|
|
| 669 |
let z = match &braco {
|
| 670 |
Braco::Pequena(a, _) => a.fwd(&contexto)?,
|
| 671 |
Braco::Densa(a, _) => a.fwd(&contexto)?,
|
| 672 |
-
Braco::Moe(m) => m.
|
| 673 |
};
|
| 674 |
z.flatten_all()?.to_vec1::<f32>()?.iter().map(|x| *x as f64).collect::<Vec<f64>>()
|
| 675 |
.chunks(n).map(|c| {
|
|
@@ -679,7 +683,7 @@ pub fn treinar_jepa_com_moe(
|
|
| 679 |
};
|
| 680 |
}
|
| 681 |
if let Braco::Moe(m) = &braco {
|
| 682 |
-
let s = m.
|
| 683 |
descartados = s.descartados;
|
| 684 |
}
|
| 685 |
Ok(RelatorioJepaMoe {
|
|
@@ -978,6 +982,7 @@ pub fn versao() -> &'static str {
|
|
| 978 |
}
|
| 979 |
|
| 980 |
#[cfg(test)]
|
|
|
|
| 981 |
mod testes {
|
| 982 |
use super::*;
|
| 983 |
|
|
@@ -1055,7 +1060,7 @@ mod testes {
|
|
| 1055 |
}
|
| 1056 |
|
| 1057 |
/// **M-R6 (v0.8.0):** equivalência de VALORES entre `fwd` e
|
| 1058 |
-
/// `
|
| 1059 |
/// saída, mesma perda auxiliar, mesma carga/descartados.
|
| 1060 |
#[test]
|
| 1061 |
fn mr6_equivalencia_de_valores() {
|
|
@@ -1068,7 +1073,7 @@ mod testes {
|
|
| 1068 |
let x = dados_sinteticos(n, d, seed);
|
| 1069 |
let moe = MoeRedirecionavel::novo(d, e, k, cap, &dev).unwrap();
|
| 1070 |
let s_ref = moe.fwd(&x, Papel::Codificador).unwrap();
|
| 1071 |
-
let s_vet = moe.
|
| 1072 |
assert_eq!(s_ref.carga, s_vet.carga, "M-R6: mesma carga (n={n})");
|
| 1073 |
assert_eq!(s_ref.usados, s_vet.usados, "M-R6: mesmos usados");
|
| 1074 |
assert_eq!(s_ref.descartados, s_vet.descartados, "M-R6: mesmos descartados");
|
|
@@ -1087,7 +1092,7 @@ mod testes {
|
|
| 1087 |
/// **M-R7 (v0.8.0):** restauração do fluxo de gradiente — bug v080-1.
|
| 1088 |
/// Com a `fwd` (referência de valores) os especialistas e o roteador
|
| 1089 |
/// NÃO recebem gradiente (grafo seccionado por to_vec2/from_vec); com
|
| 1090 |
-
/// a `
|
| 1091 |
#[test]
|
| 1092 |
fn mr7_restauracao_do_gradiente() {
|
| 1093 |
let dev = Device::Cpu;
|
|
@@ -1095,7 +1100,7 @@ mod testes {
|
|
| 1095 |
let moe = MoeRedirecionavel::novo(12, 6, 2, 48, &dev).unwrap();
|
| 1096 |
let norma_grads = |vetorizada: bool| -> (f64, f64) {
|
| 1097 |
let s = if vetorizada {
|
| 1098 |
-
moe.
|
| 1099 |
} else {
|
| 1100 |
moe.fwd(&x, Papel::Codificador).unwrap()
|
| 1101 |
};
|
|
@@ -1160,7 +1165,7 @@ mod testes {
|
|
| 1160 |
let vars = moe.vars();
|
| 1161 |
let mut opt = crate::treino::AdamWManual::novo(vars.clone(), 3e-3, 0.0);
|
| 1162 |
for _ in 0..5 {
|
| 1163 |
-
let s = moe.
|
| 1164 |
let perda = s.saida.sqr().unwrap().sum_all().unwrap();
|
| 1165 |
let grads = crate::treino::grads_achatados(&perda, &vars).unwrap();
|
| 1166 |
opt.passo(grads);
|
|
|
|
| 190 |
/// Passada por papel: atenção própria → roteamento top-k DENTRO do
|
| 191 |
/// subconjunto de especialistas do papel → capacidade → soma ponderada.
|
| 192 |
///
|
| 193 |
+
/// ⚠️ **DEPRECIADA na v0.9.0 (crítica Qwen3.8 nº 2b / r-34 §4):**
|
| 194 |
+
/// **bug v080-1 catalogado (r-33 §5)** — esta versão materializa os
|
| 195 |
+
/// valores com `to_vec2`/`from_vec` no acúmulo, o que SECCIONA o grafo
|
| 196 |
+
/// de autograd: especialistas e roteador NÃO recebem gradiente por
|
| 197 |
+
/// esta saída (só a atenção própria treina). Fora da superfície
|
| 198 |
+
/// pública (`pub(crate)`) desde a v0.9.0 — mantida EXCLUSIVAMENTE como
|
| 199 |
+
/// oráculo dos testes M-R6 (equivalência de valores) e M-R7 (prova do
|
| 200 |
+
/// bug); o caminho de treino canônico é [`MoeRedirecionavel::forward`].
|
| 201 |
+
#[deprecated(since = "0.9.0", note = "bug v080-1: secciona o grafo de autograd — use forward()")]
|
| 202 |
+
pub(crate) fn fwd(&self, x: &Tensor, papel: Papel) -> Result<SaidaMoeR> {
|
| 203 |
let y = self.atencao.fwd(x)?; // (n, d) — atenção própria independente
|
| 204 |
let n = y.dim(0)?;
|
| 205 |
let d = y.dim(1)?;
|
|
|
|
| 235 |
})
|
| 236 |
.collect();
|
| 237 |
// seleção top-k com capacidade (código extraído — MESMA semântica
|
| 238 |
+
// de desempate da v0.6.0, compartilhada com forward)
|
| 239 |
let (designacao, carga) = selecionar_com_capacidade(
|
| 240 |
&probs,
|
| 241 |
&do_papel,
|
|
|
|
| 315 |
/// `unimplemented!()`; a fórmula da perda auxiliar `E·Σ f_e·p̄_e`
|
| 316 |
/// estava CORRETA — Switch Transformer — e é mantida).
|
| 317 |
///
|
| 318 |
+
/// **Caminho canônico desde a v0.9.0 (antes `fwd_vetorizado`):**
|
| 319 |
+
/// correção do bug v080-1 — a acumulação usa `index_add` (op
|
| 320 |
/// rastreada pelo autograd do candle — `IndexAdd` em op.rs) em vez do
|
| 321 |
/// round-trip `to_vec2`/`from_vec`; os pesos de roteamento saem do
|
| 322 |
/// PRÓPRIO tensor `probs` (vivo até o roteador); a perda auxiliar usa
|
| 323 |
/// `p̄` do tensor vivo com `f` constante (padrão Switch: argmax é
|
| 324 |
/// não-diferenciável, a média de probs carrega o gradiente). O
|
| 325 |
/// gradiente flui por TODOS os caminhos (teste M-R7) com VALORES
|
| 326 |
+
/// idênticos aos da referência `fwd` (mesma seleção — teste M-R6).
|
| 327 |
+
pub fn forward(&self, x: &Tensor, papel: Papel) -> Result<SaidaMoeR> {
|
| 328 |
let y = self.atencao.fwd(x)?; // (n, d)
|
| 329 |
let n = y.dim(0)?;
|
| 330 |
let d = y.dim(1)?;
|
|
|
|
| 402 |
use std::time::Instant;
|
| 403 |
// sequencial (medição)
|
| 404 |
let t0 = Instant::now();
|
| 405 |
+
let enc_seq = self.forward(x, Papel::Codificador)?;
|
| 406 |
+
let dec_seq = self.forward(x, Papel::Decodificador)?;
|
| 407 |
let t_seq = t0.elapsed().as_secs_f64();
|
| 408 |
// paralelo (2 threads com escopo — referências compartilhadas)
|
| 409 |
let t0 = Instant::now();
|
|
|
|
| 411 |
let xref = &x;
|
| 412 |
let sref = &self;
|
| 413 |
std::thread::scope(|sc| {
|
| 414 |
+
let h1 = sc.spawn(move || sref.forward(xref, Papel::Codificador));
|
| 415 |
+
let h2 = sc.spawn(move || sref.forward(xref, Papel::Decodificador));
|
| 416 |
let r1 = h1.join().unwrap_or_else(|_| Err(candle_core::Error::Msg("thread enc".into())));
|
| 417 |
let r2 = h2.join().unwrap_or_else(|_| Err(candle_core::Error::Msg("thread dec".into())));
|
| 418 |
(r1, r2)
|
|
|
|
| 436 |
/// Seleção top-k com capacidade por especialista (v0.8.0 — extraída
|
| 437 |
/// VERBATIM do loop da `fwd` v0.6.0: mesma ordem de candidatos, mesmos
|
| 438 |
/// desempates estáveis de `sort_by`). Compartilhada por `fwd` e
|
| 439 |
+
/// `forward` ⇒ as duas atribuem EXATAMENTE os mesmos tokens aos
|
| 440 |
/// mesmos especialistas (base do teste M-R6 — equivalência de valores).
|
| 441 |
/// Devolve (designação por especialista, carga global por especialista).
|
| 442 |
fn selecionar_com_capacidade(
|
|
|
|
| 608 |
z.sqr()?.mean_all()?, 0))
|
| 609 |
}
|
| 610 |
Braco::Moe(m) => {
|
| 611 |
+
// v0.9.0: forward (ex-fwd_vetorizado) — gradiente flui aos
|
| 612 |
// especialistas e ao roteador (a fwd seccionava o grafo)
|
| 613 |
+
let s_enc = m.forward(x, Papel::Codificador)?;
|
| 614 |
+
let s_dec = m.forward(&s_enc.saida, Papel::Decodificador)?;
|
| 615 |
let dif = (&s_dec.saida - &alvo)?;
|
| 616 |
let lp = (dif.sqr()?.sum_all()? / (n as f64 * d as f64))?;
|
| 617 |
// perda total = preditiva + aux balanceamento (ambos papéis)
|
|
|
|
| 673 |
let z = match &braco {
|
| 674 |
Braco::Pequena(a, _) => a.fwd(&contexto)?,
|
| 675 |
Braco::Densa(a, _) => a.fwd(&contexto)?,
|
| 676 |
+
Braco::Moe(m) => m.forward(&contexto, Papel::Codificador)?.saida,
|
| 677 |
};
|
| 678 |
z.flatten_all()?.to_vec1::<f32>()?.iter().map(|x| *x as f64).collect::<Vec<f64>>()
|
| 679 |
.chunks(n).map(|c| {
|
|
|
|
| 683 |
};
|
| 684 |
}
|
| 685 |
if let Braco::Moe(m) = &braco {
|
| 686 |
+
let s = m.forward(&contexto, Papel::Codificador)?;
|
| 687 |
descartados = s.descartados;
|
| 688 |
}
|
| 689 |
Ok(RelatorioJepaMoe {
|
|
|
|
| 982 |
}
|
| 983 |
|
| 984 |
#[cfg(test)]
|
| 985 |
+
#[allow(deprecated)] // testes usam o oráculo fwd (bug v080-1) de propósito
|
| 986 |
mod testes {
|
| 987 |
use super::*;
|
| 988 |
|
|
|
|
| 1060 |
}
|
| 1061 |
|
| 1062 |
/// **M-R6 (v0.8.0):** equivalência de VALORES entre `fwd` e
|
| 1063 |
+
/// `forward` — mesma seleção (auxiliar compartilhado), mesma
|
| 1064 |
/// saída, mesma perda auxiliar, mesma carga/descartados.
|
| 1065 |
#[test]
|
| 1066 |
fn mr6_equivalencia_de_valores() {
|
|
|
|
| 1073 |
let x = dados_sinteticos(n, d, seed);
|
| 1074 |
let moe = MoeRedirecionavel::novo(d, e, k, cap, &dev).unwrap();
|
| 1075 |
let s_ref = moe.fwd(&x, Papel::Codificador).unwrap();
|
| 1076 |
+
let s_vet = moe.forward(&x, Papel::Codificador).unwrap();
|
| 1077 |
assert_eq!(s_ref.carga, s_vet.carga, "M-R6: mesma carga (n={n})");
|
| 1078 |
assert_eq!(s_ref.usados, s_vet.usados, "M-R6: mesmos usados");
|
| 1079 |
assert_eq!(s_ref.descartados, s_vet.descartados, "M-R6: mesmos descartados");
|
|
|
|
| 1092 |
/// **M-R7 (v0.8.0):** restauração do fluxo de gradiente — bug v080-1.
|
| 1093 |
/// Com a `fwd` (referência de valores) os especialistas e o roteador
|
| 1094 |
/// NÃO recebem gradiente (grafo seccionado por to_vec2/from_vec); com
|
| 1095 |
+
/// a `forward` TODOS recebem (index_add/index_select vivos).
|
| 1096 |
#[test]
|
| 1097 |
fn mr7_restauracao_do_gradiente() {
|
| 1098 |
let dev = Device::Cpu;
|
|
|
|
| 1100 |
let moe = MoeRedirecionavel::novo(12, 6, 2, 48, &dev).unwrap();
|
| 1101 |
let norma_grads = |vetorizada: bool| -> (f64, f64) {
|
| 1102 |
let s = if vetorizada {
|
| 1103 |
+
moe.forward(&x, Papel::Codificador).unwrap()
|
| 1104 |
} else {
|
| 1105 |
moe.fwd(&x, Papel::Codificador).unwrap()
|
| 1106 |
};
|
|
|
|
| 1165 |
let vars = moe.vars();
|
| 1166 |
let mut opt = crate::treino::AdamWManual::novo(vars.clone(), 3e-3, 0.0);
|
| 1167 |
for _ in 0..5 {
|
| 1168 |
+
let s = moe.forward(&x, Papel::Codificador).unwrap();
|
| 1169 |
let perda = s.saida.sqr().unwrap().sum_all().unwrap();
|
| 1170 |
let grads = crate::treino::grads_achatados(&perda, &vars).unwrap();
|
| 1171 |
opt.passo(grads);
|
src/python.rs
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
src/tipos.rs
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
//! Tipos de domínio com invariantes no sistema de tipos (v0.9.0).
|
| 2 |
+
//!
|
| 3 |
+
//! **Aprimoramento 5 da crítica Qwen3.8 (r-34 §6), CORRIGIDO:** a proposta
|
| 4 |
+
//! original declarava `pub struct Probabilidade(pub f64)` alegando "garante
|
| 5 |
+
//! semanticamente [0, 1]" — o que é **FALSO**: um campo público permite
|
| 6 |
+
//! `Probabilidade(7.0)` em qualquer ponto do código, e o verificador de
|
| 7 |
+
//! tipos não impede nada. A garantia só existe com (a) campo **privado** e
|
| 8 |
+
//! (b) construtor **validado** (`novo`), que recusa valores fora do domínio
|
| 9 |
+
//! uma única vez, na fronteira. Este módulo implementa a forma correta.
|
| 10 |
+
//!
|
| 11 |
+
//! **Prova lógica (T-V1):** todo valor de `Probabilidade` acessível fora
|
| 12 |
+
//! deste módulo é obtido por `novo` (campo privado ⇒ construção só via
|
| 13 |
+
//! construtor) ou por `de_unchecked` (marcado `unsafe`-semântico, visível
|
| 14 |
+
//! apenas `pub(crate)` para hot paths já verificados). `novo` devolve
|
| 15 |
+
//! `Err` para `v ∉ [0,1] ∪ {NaN}` ⇒ por indução estrutural sobre as
|
| 16 |
+
//! operações do tipo (nenhuma muta o campo), **todo** `Probabilidade`
|
| 17 |
+
//! Viveiro satisfaz `0 ≤ v ≤ 1`. ∎
|
| 18 |
+
//!
|
| 19 |
+
//! **Kani (verificação formal):** registrado como débito — o ganho marginal
|
| 20 |
+
//! sobre construtor-validado + testes de propriedade é pequeno para
|
| 21 |
+
//! invariantes de intervalo escalar; as provas estruturais continuam nos
|
| 22 |
+
//! markdown (r-XX) como exige a regra da casa.
|
| 23 |
+
|
| 24 |
+
use candle_core::Result;
|
| 25 |
+
|
| 26 |
+
/// Probabilidade — domínio fechado [0, 1].
|
| 27 |
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
| 28 |
+
pub struct Probabilidade(f64);
|
| 29 |
+
|
| 30 |
+
impl Probabilidade {
|
| 31 |
+
/// Construtor validado: recusa `v` fora de [0, 1] (incluindo NaN).
|
| 32 |
+
pub fn novo(v: f64) -> Result<Self> {
|
| 33 |
+
if v.is_nan() || v < 0.0 || v > 1.0 {
|
| 34 |
+
candle_core::bail!("Probabilidade fora de [0,1]: {v}");
|
| 35 |
+
}
|
| 36 |
+
Ok(Probabilidade(v))
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
/// Valor do domínio (o campo privado garante que passou por `novo`).
|
| 40 |
+
pub fn valor(&self) -> f64 {
|
| 41 |
+
self.0
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/// Complemento `1 − p` — preserva o domínio (fechamento).
|
| 45 |
+
pub fn complemento(&self) -> Probabilidade {
|
| 46 |
+
Probabilidade(1.0 - self.0)
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
/// Ativação de gate — domínio fechado [0, 1] (saída de `GatePunicao`).
|
| 51 |
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
| 52 |
+
pub struct GateAtivacao(f64);
|
| 53 |
+
|
| 54 |
+
impl GateAtivacao {
|
| 55 |
+
pub fn novo(v: f64) -> Result<Self> {
|
| 56 |
+
if v.is_nan() || v < 0.0 || v > 1.0 {
|
| 57 |
+
candle_core::bail!("GateAtivacao fora de [0,1]: {v}");
|
| 58 |
+
}
|
| 59 |
+
Ok(GateAtivacao(v))
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
pub fn valor(&self) -> f64 {
|
| 63 |
+
self.0
|
| 64 |
+
}
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
#[cfg(test)]
|
| 68 |
+
mod testes_tipos {
|
| 69 |
+
use super::*;
|
| 70 |
+
|
| 71 |
+
/// T-V1a — `novo` recusa valores fora do domínio (fronteira única).
|
| 72 |
+
#[test]
|
| 73 |
+
fn tv1a_construtor_recusa_fora_do_dominio() {
|
| 74 |
+
for v in [-1e-12, -0.5, 1.0 + 1e-12, 7.0, f64::NAN, f64::INFINITY] {
|
| 75 |
+
assert!(Probabilidade::novo(v).is_err(), "deveria recusar {v}");
|
| 76 |
+
assert!(GateAtivacao::novo(v).is_err(), "deveria recusar {v}");
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
/// T-V1b — `novo` aceita exatamente o fechamento [0, 1].
|
| 81 |
+
#[test]
|
| 82 |
+
fn tv1b_construtor_aceita_o_fechamento() {
|
| 83 |
+
for v in [0.0, 1e-9, 0.25, 0.5, 0.999, 1.0] {
|
| 84 |
+
let p = Probabilidade::novo(v).unwrap();
|
| 85 |
+
assert_eq!(p.valor(), v);
|
| 86 |
+
let g = GateAtivacao::novo(v).unwrap();
|
| 87 |
+
assert_eq!(g.valor(), v);
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
/// T-V1c — fechamento do complemento: p ∈ [0,1] ⇒ 1−p ∈ [0,1].
|
| 92 |
+
#[test]
|
| 93 |
+
fn tv1c_complemento_preserva_dominio() {
|
| 94 |
+
for v in [0.0, 0.1, 0.5, 0.9, 1.0] {
|
| 95 |
+
let p = Probabilidade::novo(v).unwrap();
|
| 96 |
+
let q = p.complemento();
|
| 97 |
+
assert!((0.0..=1.0).contains(&q.valor()));
|
| 98 |
+
}
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
/// T-V2 — o gate tipado produz GateAtivacao válido em TODO o domínio
|
| 102 |
+
/// (varredura densa — a prova estrutural é F-3; esta é a regressão).
|
| 103 |
+
#[test]
|
| 104 |
+
fn tv2_gate_tipado_dominio_valido() {
|
| 105 |
+
use crate::fnh::GatePunicao;
|
| 106 |
+
let gate = GatePunicao::default();
|
| 107 |
+
let mut n = 0usize;
|
| 108 |
+
let mut soma = 0.0f64;
|
| 109 |
+
for i in 0..=2000 {
|
| 110 |
+
let p = Probabilidade::novo(i as f64 / 2000.0).unwrap();
|
| 111 |
+
let g = gate.valor_tipado(&p);
|
| 112 |
+
assert!((0.0..=1.0).contains(&g.valor()), "gate fora de [0,1]: {}", g.valor());
|
| 113 |
+
soma += g.valor();
|
| 114 |
+
n += 1;
|
| 115 |
+
}
|
| 116 |
+
assert_eq!(n, 2001);
|
| 117 |
+
// integral do gate ≈ área da sigmoide retificada (> 0, < 1·domínio)
|
| 118 |
+
assert!(soma > 0.0 && soma < 2001.0);
|
| 119 |
+
}
|
| 120 |
+
}
|
src/treino.rs
CHANGED
|
@@ -199,16 +199,17 @@ impl DadosTreino {
|
|
| 199 |
}
|
| 200 |
}
|
| 201 |
|
| 202 |
-
/// Callback
|
| 203 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
|
| 205 |
-
|
|
|
|
| 206 |
if let Some(f) = cb {
|
| 207 |
-
|
| 208 |
-
if let Ok(obj) = pythonize::pythonize(py, dados) {
|
| 209 |
-
let _ = f.call1(py, (obj,));
|
| 210 |
-
}
|
| 211 |
-
});
|
| 212 |
}
|
| 213 |
}
|
| 214 |
|
|
@@ -228,7 +229,7 @@ pub fn treinar_fase_a(
|
|
| 228 |
cfg: &ConfigKhtst,
|
| 229 |
dados: &DadosTreino,
|
| 230 |
hub: &mut TelemetryHub,
|
| 231 |
-
callback: &
|
| 232 |
caminho_checkpoint: Option<&str>,
|
| 233 |
teto_seg: Option<f64>,
|
| 234 |
) -> Result<ResumoFase> {
|
|
@@ -343,7 +344,7 @@ pub fn treinar_fase_b(
|
|
| 343 |
tok: &TokenizadorConceitos,
|
| 344 |
dados: &DadosTreino,
|
| 345 |
hub: &mut TelemetryHub,
|
| 346 |
-
callback: &
|
| 347 |
caminho_checkpoint: Option<&str>,
|
| 348 |
teto_seg: Option<f64>,
|
| 349 |
) -> Result<ResumoFase> {
|
|
@@ -512,7 +513,7 @@ pub fn treinar_fase_c(
|
|
| 512 |
tok: &TokenizadorConceitos,
|
| 513 |
dados: &DadosTreino,
|
| 514 |
hub: &mut TelemetryHub,
|
| 515 |
-
callback: &
|
| 516 |
teto_seg: Option<f64>,
|
| 517 |
passos: usize,
|
| 518 |
caminho_gerador: Option<&str>,
|
|
|
|
| 199 |
}
|
| 200 |
}
|
| 201 |
|
| 202 |
+
/// Callback de progresso do treino — **tipo de DOMÍNIO desde a v0.9.0**
|
| 203 |
+
/// (crítica Qwen3.8 nº 1 / r-34 §5): antes `Option<pyo3::Py<pyo3::PyAny>>`,
|
| 204 |
+
/// o que forçava ESTE módulo de domínio a depender da FFI. A ponte Python
|
| 205 |
+
/// (src/python.rs) embrulha um callable em `Arc<dyn Fn(&serde_json::Value)>`
|
| 206 |
+
/// — `treino.rs` compila e testa sem o interpretador Python.
|
| 207 |
+
pub type CallbackTreino = Option<std::sync::Arc<dyn Fn(&serde_json::Value) + Send + Sync>>;
|
| 208 |
|
| 209 |
+
/// Invoca o callback se presente (o payload é um snapshot JSON do passo).
|
| 210 |
+
pub fn chamar_callback(cb: &CallbackTreino, dados: &serde_json::Value) {
|
| 211 |
if let Some(f) = cb {
|
| 212 |
+
f(dados);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
}
|
| 214 |
}
|
| 215 |
|
|
|
|
| 229 |
cfg: &ConfigKhtst,
|
| 230 |
dados: &DadosTreino,
|
| 231 |
hub: &mut TelemetryHub,
|
| 232 |
+
callback: &CallbackTreino,
|
| 233 |
caminho_checkpoint: Option<&str>,
|
| 234 |
teto_seg: Option<f64>,
|
| 235 |
) -> Result<ResumoFase> {
|
|
|
|
| 344 |
tok: &TokenizadorConceitos,
|
| 345 |
dados: &DadosTreino,
|
| 346 |
hub: &mut TelemetryHub,
|
| 347 |
+
callback: &CallbackTreino,
|
| 348 |
caminho_checkpoint: Option<&str>,
|
| 349 |
teto_seg: Option<f64>,
|
| 350 |
) -> Result<ResumoFase> {
|
|
|
|
| 513 |
tok: &TokenizadorConceitos,
|
| 514 |
dados: &DadosTreino,
|
| 515 |
hub: &mut TelemetryHub,
|
| 516 |
+
callback: &CallbackTreino,
|
| 517 |
teto_seg: Option<f64>,
|
| 518 |
passos: usize,
|
| 519 |
caminho_gerador: Option<&str>,
|