react-native-executorch 0.10.6 → 0.10.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/fetcher/telemetry.js +1 -1
- package/package.json +1 -1
- package/react-native-executorch.podspec +2 -0
- package/src/fetcher/telemetry.ts +1 -1
- package/third-party/common/phonemis/CMakeLists.txt +70 -14
- package/third-party/common/phonemis/README.md +183 -33
- package/third-party/common/phonemis/THIRD_PARTY_NOTICES.md +57 -0
- package/third-party/common/phonemis/knowledge/code_style.md +642 -0
- package/third-party/common/phonemis/licenses/Unicode-3.0.txt +39 -0
- package/third-party/common/phonemis/licenses/misaki-Apache-2.0.txt +201 -0
- package/third-party/common/phonemis/licenses/nlohmann-json-MIT.txt +21 -0
- package/third-party/common/phonemis/licenses/xsimd-BSD-3-Clause.txt +29 -0
- package/third-party/common/phonemis/src/phonemis/base/config.h +6 -0
- package/third-party/common/phonemis/src/phonemis/base/ipipeline.cpp +75 -0
- package/third-party/common/phonemis/src/phonemis/base/ipipeline.h +21 -0
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/constants.h +2 -5
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/lexicon_phonemizer.cpp +3 -4
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.cpp +17 -8
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/neural_phonemizer.h +4 -0
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.cpp +21 -6
- package/third-party/common/phonemis/src/phonemis/base/phonemizer/nn/tokenizer.h +13 -4
- package/third-party/common/phonemis/src/phonemis/base/pipeline.cpp +8 -0
- package/third-party/common/phonemis/src/phonemis/base/pipeline.h +19 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.cpp +37 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/conditions.h +45 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/constants.h +10 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/context.cpp +105 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/context.h +49 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/document.cpp +173 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/document.h +67 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/text.cpp +75 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/text.h +60 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/common/types.h +18 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/config.h +53 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layer.h +9 -7
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/constants.h +20 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.cpp +89 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/layer.h +35 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/normalize/types.h +16 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/kind.h +40 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/layer.h +382 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/notation.h +30 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.cpp +51 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/numerals.h +31 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern.h +30 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.cpp +17 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/pattern_set.h +31 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.cpp +811 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/patterns.h +285 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.cpp +64 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/primitives.h +23 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/num2word/types.h +94 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/sanitizer/layer.cpp +19 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/{sanitizer_layer.h → layers/sanitizer/layer.h} +8 -8
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.cpp +65 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/sym2word/layer.h +29 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.cpp +170 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/layer.h +40 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/term2word/types.h +25 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.cpp +47 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/layers/trim/layer.h +19 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.cpp +60 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/preprocessor.h +45 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/processor.cpp +6 -7
- package/third-party/common/phonemis/src/phonemis/base/processor/processor.h +14 -10
- package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.cpp +89 -52
- package/third-party/common/phonemis/src/phonemis/base/tagger/hmm_tagger.h +16 -9
- package/third-party/common/phonemis/src/phonemis/base/tokenizer/tokenizer.cpp +13 -12
- package/third-party/common/phonemis/src/phonemis/lang/de/constants.h +183 -19
- package/third-party/common/phonemis/src/phonemis/lang/de/num2word.cpp +355 -309
- package/third-party/common/phonemis/src/phonemis/lang/de/num2word.h +42 -17
- package/third-party/common/phonemis/src/phonemis/lang/de/patterns.cpp +56 -0
- package/third-party/common/phonemis/src/phonemis/lang/de/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/de/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/en/constants.h +181 -30
- package/third-party/common/phonemis/src/phonemis/lang/en/hmm_tagger.cpp +5 -7
- package/third-party/common/phonemis/src/phonemis/lang/en/num2word.cpp +232 -135
- package/third-party/common/phonemis/src/phonemis/lang/en/num2word.h +41 -16
- package/third-party/common/phonemis/src/phonemis/lang/en/pipeline.h +3 -10
- package/third-party/common/phonemis/src/phonemis/lang/es/constants.h +182 -60
- package/third-party/common/phonemis/src/phonemis/lang/es/num2word.cpp +247 -212
- package/third-party/common/phonemis/src/phonemis/lang/es/num2word.h +38 -18
- package/third-party/common/phonemis/src/phonemis/lang/es/patterns.cpp +50 -0
- package/third-party/common/phonemis/src/phonemis/lang/es/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/es/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/fr/constants.h +152 -26
- package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.cpp +252 -179
- package/third-party/common/phonemis/src/phonemis/lang/fr/num2word.h +38 -15
- package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.cpp +83 -0
- package/third-party/common/phonemis/src/phonemis/lang/fr/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/fr/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/hi/constants.h +62 -10
- package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.cpp +74 -123
- package/third-party/common/phonemis/src/phonemis/lang/hi/num2word.h +27 -16
- package/third-party/common/phonemis/src/phonemis/lang/hi/pipeline.h +5 -3
- package/third-party/common/phonemis/src/phonemis/lang/it/constants.h +122 -42
- package/third-party/common/phonemis/src/phonemis/lang/it/num2word.cpp +200 -207
- package/third-party/common/phonemis/src/phonemis/lang/it/num2word.h +30 -18
- package/third-party/common/phonemis/src/phonemis/lang/it/patterns.cpp +25 -0
- package/third-party/common/phonemis/src/phonemis/lang/it/patterns.h +15 -0
- package/third-party/common/phonemis/src/phonemis/lang/it/pipeline.h +3 -3
- package/third-party/common/phonemis/src/phonemis/lang/pl/constants.h +346 -77
- package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.cpp +631 -246
- package/third-party/common/phonemis/src/phonemis/lang/pl/num2word.h +47 -15
- package/third-party/common/phonemis/src/phonemis/lang/pl/pipeline.h +6 -6
- package/third-party/common/phonemis/src/phonemis/lang/pt/constants.h +201 -0
- package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.cpp +365 -0
- package/third-party/common/phonemis/src/phonemis/lang/pt/num2word.h +53 -0
- package/third-party/common/phonemis/src/phonemis/lang/pt/pipeline.h +4 -2
- package/third-party/common/phonemis/src/phonemis/main.cpp +42 -11
- package/third-party/common/phonemis/src/phonemis/protophone/meta.h +24 -0
- package/third-party/common/phonemis/src/phonemis/protophone/numeric.h +26 -0
- package/third-party/common/phonemis/src/phonemis/protophone/protophone.cpp +525 -0
- package/third-party/common/phonemis/src/phonemis/protophone/protophone.h +80 -0
- package/third-party/common/phonemis/src/phonemis/protophone/tensor.h +76 -0
- package/third-party/common/phonemis/src/phonemis/protophone/tensor_utils.h +89 -0
- package/third-party/common/phonemis/src/phonemis/protophone/tensor_view.h +125 -0
- package/third-party/common/phonemis/src/phonemis/protophone/types.h +43 -0
- package/third-party/common/phonemis/src/phonemis/utils/strings.h +20 -14
- package/third-party/common/phonemis/src/phonemis/utils/unicode.h +15 -1
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_arithmetic.hpp +267 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_bit.hpp +232 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_cast.hpp +43 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_complex.hpp +112 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_details.hpp +386 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_logical.hpp +240 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_math.hpp +2601 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_memory.hpp +1006 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_rounding.hpp +72 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_swizzle.hpp +260 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/common/xsimd_common_trigo.hpp +996 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/utils/shifts.hpp +82 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx.hpp +2111 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2.hpp +1591 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx2_128.hpp +170 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512bw.hpp +724 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512cd.hpp +28 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512dq.hpp +270 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512er.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512f.hpp +2919 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512ifma.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512pf.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi.hpp +76 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vbmi2.hpp +130 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512bw.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx512vnni_avx512vbmi2.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avx_128.hpp +164 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_avxvnni.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common.hpp +26 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_common_fwd.hpp +127 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_constants.hpp +393 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_emulated.hpp +787 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx.hpp +93 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_avx2.hpp +46 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma3_sse.hpp +97 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_fma4.hpp +92 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_i8mm_neon64.hpp +17 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_isa.hpp +148 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon.hpp +3580 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_neon64.hpp +1614 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_rvv.hpp +1515 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_scalar.hpp +1210 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse2.hpp +2333 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse3.hpp +66 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_1.hpp +510 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sse4_2.hpp +44 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_ssse3.hpp +186 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_sve.hpp +1186 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vsx.hpp +947 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_vxe.hpp +787 -0
- package/third-party/common/phonemis/src/third-party/xsimd/arch/xsimd_wasm.hpp +1819 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_arch.hpp +242 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_config.hpp +633 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_arm.hpp +132 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_ppc.hpp +54 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_riscv.hpp +95 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_s390x.hpp +56 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpu_features_x86.hpp +1121 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_cpuid.hpp +144 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_getauxval.hpp +159 -0
- package/third-party/common/phonemis/src/third-party/xsimd/config/xsimd_macros.hpp +78 -0
- package/third-party/common/phonemis/src/third-party/xsimd/math/xsimd_rem_pio2.hpp +707 -0
- package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_aligned_allocator.hpp +349 -0
- package/third-party/common/phonemis/src/third-party/xsimd/memory/xsimd_alignment.hpp +102 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_all_registers.hpp +57 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_api.hpp +3106 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx2_register.hpp +57 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512bw_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512cd_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512dq_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512er_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512f_register.hpp +77 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512ifma_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512pf_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi2_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vbmi_register.hpp +51 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512bw_register.hpp +54 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx512vnni_avx512vbmi2_register.hpp +53 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avx_register.hpp +79 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_avxvnni_register.hpp +44 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch.hpp +1666 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_constant.hpp +572 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_batch_fwd.hpp +41 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_common_arch.hpp +49 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_emulated_register.hpp +80 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx2_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_avx_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma3_sse_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_fma4_register.hpp +50 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_i8mm_neon64_register.hpp +55 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon64_register.hpp +55 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_neon_register.hpp +130 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_register.hpp +96 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_rvv_register.hpp +491 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse2_register.hpp +59 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse3_register.hpp +49 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_1_register.hpp +48 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sse4_2_register.hpp +48 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_ssse3_register.hpp +48 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_sve_register.hpp +216 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_traits.hpp +409 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_utils.hpp +462 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vsx_register.hpp +84 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_vxe_register.hpp +86 -0
- package/third-party/common/phonemis/src/third-party/xsimd/types/xsimd_wasm_register.hpp +59 -0
- package/third-party/common/phonemis/src/third-party/xsimd/utils/bits.hpp +122 -0
- package/third-party/common/phonemis/src/third-party/xsimd/utils/xsimd_type_traits.hpp +145 -0
- package/third-party/common/phonemis/src/third-party/xsimd/xsimd.hpp +43 -0
- package/third-party/common/phonemis/src/phonemis/base/processor/constants.h +0 -11
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/config.h +0 -16
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.cpp +0 -271
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/layer.h +0 -45
- package/third-party/common/phonemis/src/phonemis/base/processor/num2word/types.h +0 -29
- package/third-party/common/phonemis/src/phonemis/base/processor/sanitizer_layer.cpp +0 -22
- package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.cpp +0 -40
- package/third-party/common/phonemis/src/phonemis/base/processor/trim_layer.h +0 -22
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
#include "protophone.h"
|
|
2
|
+
|
|
3
|
+
#include <third-party/xsimd/xsimd.hpp>
|
|
4
|
+
|
|
5
|
+
#include <algorithm>
|
|
6
|
+
#include <array>
|
|
7
|
+
#include <cmath>
|
|
8
|
+
#include <cstring>
|
|
9
|
+
#include <stdexcept>
|
|
10
|
+
#include <thread>
|
|
11
|
+
|
|
12
|
+
namespace phonemis::protophone {
|
|
13
|
+
|
|
14
|
+
namespace {
|
|
15
|
+
|
|
16
|
+
// ---- Model architecture constants -------------------
|
|
17
|
+
// Every model shape is fixed by the architecture and hardcoded here. The sole
|
|
18
|
+
// exception is the embedding dimension, which can vary between languages and is
|
|
19
|
+
// therefore read from the embedding weight at load time (see embed_dim_).
|
|
20
|
+
constexpr size_t F = 64; // features per kernel after GLU
|
|
21
|
+
constexpr size_t K3 = 28, K5 = 20, K7 = 10; // number of kernels per conv
|
|
22
|
+
constexpr size_t TOTAL_K = K3 + K5 + K7; // 58
|
|
23
|
+
constexpr size_t KF = TOTAL_K * F; // 3712 (kernel_mixer input)
|
|
24
|
+
constexpr size_t L = 256; // hidden width
|
|
25
|
+
constexpr size_t NUM_PHONEMES = 116;
|
|
26
|
+
constexpr size_t MAX_PAD = 3; // padding for the largest kernel (k=7)
|
|
27
|
+
|
|
28
|
+
// Time-tile width for the register-blocked matmuls (kernel_mixer / shift_mlp).
|
|
29
|
+
// 2 * kTile accumulators + 2 weight registers = 10 live SIMD registers, which
|
|
30
|
+
// fits the x86 AVX2 register file while staying effective on NEON.
|
|
31
|
+
constexpr size_t kTile = 4;
|
|
32
|
+
|
|
33
|
+
// Upper bound on worker threads. Inference is a small, latency-sensitive
|
|
34
|
+
// workload, so a modest cap avoids oversubscription and keeps timings stable.
|
|
35
|
+
constexpr size_t kMaxWorkers = 4;
|
|
36
|
+
|
|
37
|
+
using batch = xsimd::batch<float>;
|
|
38
|
+
constexpr size_t W = batch::size;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* SIMD dot product of two contiguous float arrays of length n.
|
|
42
|
+
* Uses unaligned loads so it works at any row offset.
|
|
43
|
+
*/
|
|
44
|
+
inline float simd_dot(const float* a, const float* b, size_t n) {
|
|
45
|
+
batch acc(0.0f);
|
|
46
|
+
size_t i = 0;
|
|
47
|
+
for (; i + W <= n; i += W) {
|
|
48
|
+
acc = xsimd::fma(batch::load_unaligned(a + i), batch::load_unaligned(b + i), acc);
|
|
49
|
+
}
|
|
50
|
+
float result = xsimd::reduce_add(acc);
|
|
51
|
+
for (; i < n; ++i) {
|
|
52
|
+
result += a[i] * b[i];
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Computes out = bias + W * x for each of the `out_dim` rows, where W is stored
|
|
59
|
+
* row-major as [out_dim, in_dim] and x is contiguous of length `in_dim`.
|
|
60
|
+
* Optionally applies a ReLU to the result.
|
|
61
|
+
*/
|
|
62
|
+
inline void affine(const float* w, const float* bias, const float* x,
|
|
63
|
+
size_t out_dim, size_t in_dim, float* out, bool relu) {
|
|
64
|
+
for (size_t o = 0; o < out_dim; ++o) {
|
|
65
|
+
float v = bias[o] + simd_dot(w + o * in_dim, x, in_dim);
|
|
66
|
+
out[o] = relu ? std::max(v, 0.0f) : v;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Blends two source rows into a destination row using
|
|
72
|
+
* dst = w0 * src0 + w1 * src1, vectorized over the channel dimension.
|
|
73
|
+
*/
|
|
74
|
+
inline void blend_rows(const float* src0, const float* src1, float w0, float w1,
|
|
75
|
+
float* dst, size_t n) {
|
|
76
|
+
const batch vw0(w0), vw1(w1);
|
|
77
|
+
size_t i = 0;
|
|
78
|
+
for (; i + W <= n; i += W) {
|
|
79
|
+
batch r = batch::load_unaligned(src0 + i) * vw0;
|
|
80
|
+
r = xsimd::fma(batch::load_unaligned(src1 + i), vw1, r);
|
|
81
|
+
r.store_unaligned(dst + i);
|
|
82
|
+
}
|
|
83
|
+
for (; i < n; ++i) {
|
|
84
|
+
dst[i] = w0 * src0[i] + w1 * src1[i];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Grows a scratch buffer in place; never shrinks, so steady-state runs do not
|
|
89
|
+
// reallocate.
|
|
90
|
+
inline void ensure(std::vector<float, xsimd::default_allocator<float>>& buf, size_t n) {
|
|
91
|
+
if (buf.size() < n) buf.resize(n);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Process-wide worker budget, resolved once. Capped at kMaxWorkers.
|
|
95
|
+
inline size_t worker_budget() {
|
|
96
|
+
static const size_t budget = [] {
|
|
97
|
+
const unsigned hw = std::thread::hardware_concurrency();
|
|
98
|
+
return hw <= 1 ? size_t(1) : std::min<size_t>(hw, kMaxWorkers);
|
|
99
|
+
}();
|
|
100
|
+
return budget;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Minimal fork/join parallel-for over [0, n). Splits the range into one
|
|
105
|
+
* contiguous chunk per worker and invokes fn(begin, end) for each; the first
|
|
106
|
+
* chunk runs on the calling thread.
|
|
107
|
+
*
|
|
108
|
+
* Threads are only spawned when there are at least `min_per_worker` items per
|
|
109
|
+
* worker, so small / cheap workloads stay fully serial and never pay the
|
|
110
|
+
* thread-creation cost. Callers pick `min_per_worker` to reflect the per-item
|
|
111
|
+
* cost (e.g. a larger value when each item is light).
|
|
112
|
+
*/
|
|
113
|
+
template <typename Fn>
|
|
114
|
+
inline void parallel_for(size_t n, size_t min_per_worker, Fn&& fn) {
|
|
115
|
+
if (n == 0) return;
|
|
116
|
+
const size_t affordable = n / std::max<size_t>(min_per_worker, 1);
|
|
117
|
+
const size_t nthreads = std::min(worker_budget(), affordable);
|
|
118
|
+
if (nthreads <= 1) {
|
|
119
|
+
fn(size_t(0), n);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const size_t chunk = (n + nthreads - 1) / nthreads;
|
|
124
|
+
std::vector<std::thread> workers;
|
|
125
|
+
workers.reserve(nthreads - 1);
|
|
126
|
+
for (size_t begin = chunk; begin < n; begin += chunk) {
|
|
127
|
+
const size_t end = std::min(n, begin + chunk);
|
|
128
|
+
workers.emplace_back([&fn, begin, end] { fn(begin, end); });
|
|
129
|
+
}
|
|
130
|
+
fn(size_t(0), std::min(n, chunk)); // first chunk on the calling thread
|
|
131
|
+
for (std::thread& wkr : workers) wkr.join();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
} // namespace
|
|
135
|
+
|
|
136
|
+
// =============================================================================
|
|
137
|
+
// Construction & weight loading
|
|
138
|
+
// =============================================================================
|
|
139
|
+
|
|
140
|
+
Protophone::Protophone(const std::string& model_path)
|
|
141
|
+
: embedding_({0}),
|
|
142
|
+
conv3_{Tensor<float>({0}), Tensor<float>({0})},
|
|
143
|
+
conv5_{Tensor<float>({0}), Tensor<float>({0})},
|
|
144
|
+
conv7_{Tensor<float>({0}), Tensor<float>({0})},
|
|
145
|
+
mixer_{Tensor<float>({0}), Tensor<float>({0})},
|
|
146
|
+
ctc_proj_{Tensor<float>({0}), Tensor<float>({0})} {
|
|
147
|
+
load_weights(model_path);
|
|
148
|
+
|
|
149
|
+
// Fixed-size scratch for one tile of ShiftLinear shifted feature vectors.
|
|
150
|
+
shifted_.resize(kTile * L);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
void Protophone::load_weights(const std::string& model_path) {
|
|
154
|
+
std::ifstream f(model_path, std::ios::binary);
|
|
155
|
+
if (!f.is_open()) {
|
|
156
|
+
throw std::runtime_error("Failed to open model file: " + model_path);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Repacks a conv weight from PyTorch [out_ch, in_ch, k] to [out_ch, k, in_ch].
|
|
160
|
+
// After repacking, the weights of a single output channel form one contiguous
|
|
161
|
+
// run that aligns with the (also contiguous) input window, so a convolution
|
|
162
|
+
// output reduces to a single dot product of length k * in_ch.
|
|
163
|
+
auto repack_conv = [](const Tensor<float>& src) {
|
|
164
|
+
const auto& sh = src.shape();
|
|
165
|
+
const size_t oc = sh[0], ic = sh[1], k = sh[2];
|
|
166
|
+
std::vector<float> buf(oc * k * ic);
|
|
167
|
+
const float* s = src.data().data();
|
|
168
|
+
for (size_t o = 0; o < oc; ++o) {
|
|
169
|
+
for (size_t c = 0; c < ic; ++c) {
|
|
170
|
+
for (size_t j = 0; j < k; ++j) {
|
|
171
|
+
buf[(o * k + j) * ic + c] = s[(o * ic + c) * k + j];
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return Tensor<float>({oc, k, ic}, buf.data());
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// 1. Embedding. The embedding dimension is the only shape read from weights.
|
|
179
|
+
// A trailing zero row is appended so out-of-range tokens map to a zero
|
|
180
|
+
// embedding instead of reading out of bounds.
|
|
181
|
+
embedding_ = read_tensor(f, "embedding.weight");
|
|
182
|
+
const size_t vocab_size = embedding_.shape()[0];
|
|
183
|
+
embed_dim_ = embedding_.shape()[1];
|
|
184
|
+
std::vector<float> padded(embedding_.data().begin(), embedding_.data().end());
|
|
185
|
+
padded.resize((vocab_size + 1) * embed_dim_, 0.0f);
|
|
186
|
+
embedding_ = Tensor<float>({vocab_size + 1, embed_dim_}, padded.data());
|
|
187
|
+
|
|
188
|
+
// 2-4. Multi-kernel convolutions (repacked for contiguous dot products).
|
|
189
|
+
conv3_.weight = repack_conv(read_tensor(f, "conv3.weight"));
|
|
190
|
+
conv3_.bias = read_tensor(f, "conv3.bias");
|
|
191
|
+
conv5_.weight = repack_conv(read_tensor(f, "conv5.weight"));
|
|
192
|
+
conv5_.bias = read_tensor(f, "conv5.bias");
|
|
193
|
+
conv7_.weight = repack_conv(read_tensor(f, "conv7.weight"));
|
|
194
|
+
conv7_.bias = read_tensor(f, "conv7.bias");
|
|
195
|
+
|
|
196
|
+
// 5. Kernel mixer.
|
|
197
|
+
mixer_.weight = read_tensor(f, "kernel_mixer.weight");
|
|
198
|
+
mixer_.bias = read_tensor(f, "kernel_mixer.bias");
|
|
199
|
+
|
|
200
|
+
// 6-9. ShiftMLP layers.
|
|
201
|
+
for (int i = 0; i < 4; ++i) {
|
|
202
|
+
auto w = read_tensor(f, "shift_mlp.layer" + std::to_string(i) + ".weight");
|
|
203
|
+
auto b = read_tensor(f, "shift_mlp.layer" + std::to_string(i) + ".bias");
|
|
204
|
+
shift_mlp_.push_back({std::move(w), std::move(b)});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 10. CTC projection.
|
|
208
|
+
ctc_proj_.weight = read_tensor(f, "ctc_proj.weight");
|
|
209
|
+
ctc_proj_.bias = read_tensor(f, "ctc_proj.bias");
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
Tensor<float> Protophone::read_tensor(std::ifstream& f, const std::string& name) {
|
|
213
|
+
// Binary layout per tensor: <int64 num_dims> <int64 dims...> <float32 data...>
|
|
214
|
+
int64_t num_dims = 0;
|
|
215
|
+
if (!f.read(reinterpret_cast<char*>(&num_dims), sizeof(int64_t))) {
|
|
216
|
+
throw std::runtime_error("Failed to read num_dims for: " + name);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
std::vector<size_t> shape(num_dims);
|
|
220
|
+
size_t total_elements = 1;
|
|
221
|
+
for (int64_t i = 0; i < num_dims; ++i) {
|
|
222
|
+
int64_t dim;
|
|
223
|
+
f.read(reinterpret_cast<char*>(&dim), sizeof(int64_t));
|
|
224
|
+
shape[i] = static_cast<size_t>(dim);
|
|
225
|
+
total_elements *= shape[i];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
std::vector<float> data(total_elements);
|
|
229
|
+
if (!f.read(reinterpret_cast<char*>(data.data()), total_elements * sizeof(float))) {
|
|
230
|
+
throw std::runtime_error("Failed to read data for: " + name);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return Tensor<float>(shape, data.data());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// =============================================================================
|
|
237
|
+
// Inference stages
|
|
238
|
+
// =============================================================================
|
|
239
|
+
|
|
240
|
+
void Protophone::embed(const std::vector<int64_t>& tokens) {
|
|
241
|
+
// Build a zero-bordered embedding matrix of shape (S + 2*MAX_PAD, embed_dim_).
|
|
242
|
+
// The MAX_PAD zero rows on each side let the convolutions index their
|
|
243
|
+
// receptive field without any per-element boundary checks.
|
|
244
|
+
const size_t padded_rows = seq_len_ + 2 * MAX_PAD;
|
|
245
|
+
ensure(emb_padded_, padded_rows * embed_dim_);
|
|
246
|
+
std::fill(emb_padded_.begin(), emb_padded_.begin() + padded_rows * embed_dim_, 0.0f);
|
|
247
|
+
|
|
248
|
+
const float* table = embedding_.data().data();
|
|
249
|
+
const size_t vocab = embedding_.shape()[0];
|
|
250
|
+
for (size_t t = 0; t < seq_len_; ++t) {
|
|
251
|
+
size_t id = static_cast<size_t>(tokens[t]);
|
|
252
|
+
if (id >= vocab) id = vocab - 1; // trailing zero row
|
|
253
|
+
float* dst = emb_padded_.data() + (MAX_PAD + t) * embed_dim_;
|
|
254
|
+
std::memcpy(dst, table + id * embed_dim_, embed_dim_ * sizeof(float));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
void Protophone::multi_kernel_conv_glu() {
|
|
259
|
+
ensure(glu_, seq_len_ * KF);
|
|
260
|
+
|
|
261
|
+
// One work item per output kernel (K3 + K5 + K7 = TOTAL_K of them). Each item
|
|
262
|
+
// is fully independent: it reads the shared (read-only) embedding window and
|
|
263
|
+
// writes a disjoint F-wide column band of glu_, so the items can run on
|
|
264
|
+
// separate threads without any synchronization.
|
|
265
|
+
struct KernelWork {
|
|
266
|
+
const float* weight; // weights of this kernel's first (channel 0) output
|
|
267
|
+
const float* bias; // biases of this kernel's 2*F output channels
|
|
268
|
+
size_t wlen; // receptive field length = k * embed_dim_
|
|
269
|
+
size_t pad; // convolution padding for this kernel size
|
|
270
|
+
size_t glu_col; // destination column of this kernel's F features
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
std::array<KernelWork, TOTAL_K> works;
|
|
274
|
+
size_t idx = 0;
|
|
275
|
+
auto add_conv = [&](const Weights<float>& cw, size_t k, size_t pad,
|
|
276
|
+
size_t num_kernels, size_t glu_off) {
|
|
277
|
+
const float* wbase = cw.weight.data().data();
|
|
278
|
+
const float* bbase = cw.bias.data().data();
|
|
279
|
+
const size_t wlen = k * embed_dim_;
|
|
280
|
+
for (size_t kk = 0; kk < num_kernels; ++kk) {
|
|
281
|
+
works[idx++] = {wbase + kk * 2 * F * wlen, bbase + kk * 2 * F, wlen, pad,
|
|
282
|
+
glu_off + kk * F};
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
add_conv(conv3_, 3, 1, K3, 0);
|
|
286
|
+
add_conv(conv5_, 5, 2, K5, K3 * F);
|
|
287
|
+
add_conv(conv7_, 7, 3, K7, (K3 + K5) * F);
|
|
288
|
+
|
|
289
|
+
// Each kernel item is light, and the work scales with seq_len_. Only fan out
|
|
290
|
+
// for non-trivial sequences; otherwise run serially (min_per_worker == TOTAL_K
|
|
291
|
+
// forces a single chunk). For longer inputs, ~16 kernels per worker keeps the
|
|
292
|
+
// thread count modest (a few workers out of the budget).
|
|
293
|
+
const size_t min_per_worker = seq_len_ >= 4 ? 16 : TOTAL_K;
|
|
294
|
+
|
|
295
|
+
parallel_for(TOTAL_K, min_per_worker, [&](size_t begin, size_t end) {
|
|
296
|
+
float raw[2 * F]; // per-thread scratch for one kernel's 2*F conv outputs
|
|
297
|
+
|
|
298
|
+
for (size_t wi = begin; wi < end; ++wi) {
|
|
299
|
+
const KernelWork& kw = works[wi];
|
|
300
|
+
|
|
301
|
+
for (size_t t = 0; t < seq_len_; ++t) {
|
|
302
|
+
// The receptive field is a contiguous block of wlen floats starting at
|
|
303
|
+
// row (MAX_PAD - pad + t). The repacked weights match this layout, so
|
|
304
|
+
// each output channel is a single dot product.
|
|
305
|
+
const float* window =
|
|
306
|
+
emb_padded_.data() + (MAX_PAD - kw.pad + t) * embed_dim_;
|
|
307
|
+
for (size_t ch = 0; ch < 2 * F; ++ch) {
|
|
308
|
+
raw[ch] = kw.bias[ch] + simd_dot(kw.weight + ch * kw.wlen, window, kw.wlen);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// GLU: the 2*F channels are laid out as [F values | F gates]; the output
|
|
312
|
+
// is value * sigmoid(gate), vectorized over the F features.
|
|
313
|
+
float* optr = glu_.data() + t * KF + kw.glu_col;
|
|
314
|
+
size_t fe = 0;
|
|
315
|
+
for (; fe + W <= F; fe += W) {
|
|
316
|
+
batch v = batch::load_unaligned(raw + fe);
|
|
317
|
+
batch g = batch::load_unaligned(raw + F + fe);
|
|
318
|
+
batch sig = 1.0f / (1.0f + xsimd::exp(-g));
|
|
319
|
+
(v * sig).store_unaligned(optr + fe);
|
|
320
|
+
}
|
|
321
|
+
for (; fe < F; ++fe) {
|
|
322
|
+
optr[fe] = raw[fe] / (1.0f + std::exp(-raw[F + fe]));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
void Protophone::kernel_mixer() {
|
|
330
|
+
ensure(mixed_, seq_len_ * L);
|
|
331
|
+
const float* w = mixer_.weight.data().data(); // [L, KF]
|
|
332
|
+
const float* b = mixer_.bias.data().data();
|
|
333
|
+
const float* x = glu_.data(); // [S, KF]
|
|
334
|
+
const size_t S = seq_len_;
|
|
335
|
+
|
|
336
|
+
// Register-blocked GEMM: mixed[S, L] = relu(glu[S, KF] @ W^T + b), W is [L, KF].
|
|
337
|
+
//
|
|
338
|
+
// The mixer is the heaviest stage (L * KF MACs per time step), so two things
|
|
339
|
+
// matter most: hiding FMA latency and limiting weight-matrix memory traffic.
|
|
340
|
+
// - We tile the (small) time dimension by TILE. A streamed weight element
|
|
341
|
+
// W[o][c] is then reused across TILE time steps, roughly halving the
|
|
342
|
+
// load:FMA ratio versus computing one dot product at a time.
|
|
343
|
+
// - Each time step keeps two accumulators over interleaved chunks of the
|
|
344
|
+
// reduction dimension, giving 2 * TILE independent FMA chains so the
|
|
345
|
+
// accumulators are not serialized by the FMA latency.
|
|
346
|
+
for (size_t t0 = 0; t0 < S; t0 += kTile) {
|
|
347
|
+
const size_t tn = std::min(kTile, S - t0);
|
|
348
|
+
|
|
349
|
+
for (size_t o = 0; o < L; ++o) {
|
|
350
|
+
const float* wrow = w + o * KF;
|
|
351
|
+
batch acc0[kTile];
|
|
352
|
+
batch acc1[kTile];
|
|
353
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
354
|
+
acc0[i] = batch(0.0f);
|
|
355
|
+
acc1[i] = batch(0.0f);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
size_t c = 0;
|
|
359
|
+
for (; c + 2 * W <= KF; c += 2 * W) {
|
|
360
|
+
const batch wb0 = batch::load_unaligned(wrow + c);
|
|
361
|
+
const batch wb1 = batch::load_unaligned(wrow + c + W);
|
|
362
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
363
|
+
const float* px = x + (t0 + i) * KF + c;
|
|
364
|
+
acc0[i] = xsimd::fma(wb0, batch::load_unaligned(px), acc0[i]);
|
|
365
|
+
acc1[i] = xsimd::fma(wb1, batch::load_unaligned(px + W), acc1[i]);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// A single remaining full-width chunk, if KF is not a multiple of 2 * W.
|
|
369
|
+
if (c + W <= KF) {
|
|
370
|
+
const batch wb0 = batch::load_unaligned(wrow + c);
|
|
371
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
372
|
+
acc0[i] = xsimd::fma(wb0, batch::load_unaligned(x + (t0 + i) * KF + c), acc0[i]);
|
|
373
|
+
}
|
|
374
|
+
c += W;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Horizontal reduce + bias + scalar tail + ReLU.
|
|
378
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
379
|
+
float v = b[o] + xsimd::reduce_add(acc0[i] + acc1[i]);
|
|
380
|
+
const float* px = x + (t0 + i) * KF;
|
|
381
|
+
for (size_t cc = c; cc < KF; ++cc) v += wrow[cc] * px[cc];
|
|
382
|
+
mixed_[(t0 + i) * L + o] = std::max(v, 0.0f);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
void Protophone::upsample_linear() {
|
|
389
|
+
// Mirrors F.interpolate(mode='linear', align_corners=False) along the time
|
|
390
|
+
// axis. Operating directly on the (S, L) row-major layout means each output
|
|
391
|
+
// step is a SIMD blend of two contiguous input rows (no transpose needed).
|
|
392
|
+
ensure(shift_a_, up_len_ * L);
|
|
393
|
+
const float scale = static_cast<float>(seq_len_) / static_cast<float>(up_len_);
|
|
394
|
+
const float* src = mixed_.data();
|
|
395
|
+
for (size_t i = 0; i < up_len_; ++i) {
|
|
396
|
+
float pos = scale * (static_cast<float>(i) + 0.5f) - 0.5f;
|
|
397
|
+
if (pos < 0.0f) pos = 0.0f;
|
|
398
|
+
const size_t i0 = static_cast<size_t>(pos);
|
|
399
|
+
const size_t i1 = std::min(i0 + 1, seq_len_ - 1);
|
|
400
|
+
const float l1 = pos - static_cast<float>(i0);
|
|
401
|
+
blend_rows(src + i0 * L, src + i1 * L, 1.0f - l1, l1, shift_a_.data() + i * L, L);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
void Protophone::shift_mlp() {
|
|
406
|
+
// Four residual ShiftLinear layers with dilations 1, 2, 4, 8. We ping-pong
|
|
407
|
+
// between two buffers because the channel shift reads neighbouring time steps,
|
|
408
|
+
// which would be corrupted by an in-place update.
|
|
409
|
+
ensure(shift_b_, up_len_ * L);
|
|
410
|
+
constexpr size_t G = L / 4; // 64: look-ahead / look-back / stay group size
|
|
411
|
+
const size_t dilations[4] = {1, 2, 4, 8};
|
|
412
|
+
const size_t T = up_len_;
|
|
413
|
+
|
|
414
|
+
Buffer* in = &shift_a_;
|
|
415
|
+
Buffer* out = &shift_b_;
|
|
416
|
+
|
|
417
|
+
for (int layer = 0; layer < 4; ++layer) {
|
|
418
|
+
const size_t d = dilations[layer];
|
|
419
|
+
const float* w = shift_mlp_[layer].weight.data().data(); // [L, L]
|
|
420
|
+
const float* b = shift_mlp_[layer].bias.data().data();
|
|
421
|
+
const float* xin = in->data();
|
|
422
|
+
float* xout = out->data();
|
|
423
|
+
|
|
424
|
+
// Same register-blocked GEMM as kernel_mixer: tile the time dimension so a
|
|
425
|
+
// streamed weight element W[o][c] is reused across the tile, and keep two
|
|
426
|
+
// accumulators per time step to break the FMA latency chain. The matmul
|
|
427
|
+
// operates on the per-tile shifted feature vectors assembled up front.
|
|
428
|
+
for (size_t t0 = 0; t0 < T; t0 += kTile) {
|
|
429
|
+
const size_t tn = std::min(kTile, T - t0);
|
|
430
|
+
|
|
431
|
+
// Assemble the shifted feature vector for each time step in the tile:
|
|
432
|
+
// [0, G) <- look ahead : xin[t + d] (zero past the end)
|
|
433
|
+
// [G, 2G) <- look behind : xin[t - d] (zero before the start)
|
|
434
|
+
// [2G, L) <- stay : xin[t]
|
|
435
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
436
|
+
const size_t t = t0 + i;
|
|
437
|
+
float* sh = shifted_.data() + i * L;
|
|
438
|
+
if (t + d < T) {
|
|
439
|
+
std::memcpy(sh, xin + (t + d) * L, G * sizeof(float));
|
|
440
|
+
} else {
|
|
441
|
+
std::fill(sh, sh + G, 0.0f);
|
|
442
|
+
}
|
|
443
|
+
if (t >= d) {
|
|
444
|
+
std::memcpy(sh + G, xin + (t - d) * L + G, G * sizeof(float));
|
|
445
|
+
} else {
|
|
446
|
+
std::fill(sh + G, sh + 2 * G, 0.0f);
|
|
447
|
+
}
|
|
448
|
+
std::memcpy(sh + 2 * G, xin + t * L + 2 * G, (L - 2 * G) * sizeof(float));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
for (size_t o = 0; o < L; ++o) {
|
|
452
|
+
const float* wrow = w + o * L;
|
|
453
|
+
batch acc0[kTile];
|
|
454
|
+
batch acc1[kTile];
|
|
455
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
456
|
+
acc0[i] = batch(0.0f);
|
|
457
|
+
acc1[i] = batch(0.0f);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
size_t c = 0;
|
|
461
|
+
for (; c + 2 * W <= L; c += 2 * W) {
|
|
462
|
+
const batch wb0 = batch::load_unaligned(wrow + c);
|
|
463
|
+
const batch wb1 = batch::load_unaligned(wrow + c + W);
|
|
464
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
465
|
+
const float* ps = shifted_.data() + i * L + c;
|
|
466
|
+
acc0[i] = xsimd::fma(wb0, batch::load_unaligned(ps), acc0[i]);
|
|
467
|
+
acc1[i] = xsimd::fma(wb1, batch::load_unaligned(ps + W), acc1[i]);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (c + W <= L) {
|
|
471
|
+
const batch wb0 = batch::load_unaligned(wrow + c);
|
|
472
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
473
|
+
acc0[i] = xsimd::fma(wb0, batch::load_unaligned(shifted_.data() + i * L + c), acc0[i]);
|
|
474
|
+
}
|
|
475
|
+
c += W;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ReLU(W * shifted + b) + residual.
|
|
479
|
+
for (size_t i = 0; i < tn; ++i) {
|
|
480
|
+
float v = b[o] + xsimd::reduce_add(acc0[i] + acc1[i]);
|
|
481
|
+
const float* ps = shifted_.data() + i * L;
|
|
482
|
+
for (size_t cc = c; cc < L; ++cc) v += wrow[cc] * ps[cc];
|
|
483
|
+
xout[(t0 + i) * L + o] = std::max(v, 0.0f) + xin[(t0 + i) * L + o];
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
std::swap(in, out);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// After four swaps the latest activations live back in shift_a_.
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
Tensor<float> Protophone::ctc_projection() {
|
|
495
|
+
Tensor<float> logits({up_len_, NUM_PHONEMES});
|
|
496
|
+
float* out = logits.view().data();
|
|
497
|
+
const float* w = ctc_proj_.weight.data().data(); // [NUM_PHONEMES, L]
|
|
498
|
+
const float* b = ctc_proj_.bias.data().data();
|
|
499
|
+
const float* x = shift_a_.data();
|
|
500
|
+
for (size_t t = 0; t < up_len_; ++t) {
|
|
501
|
+
affine(w, b, x + t * L, NUM_PHONEMES, L, out + t * NUM_PHONEMES, /*relu=*/false);
|
|
502
|
+
}
|
|
503
|
+
return logits;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// =============================================================================
|
|
507
|
+
// Forward pass
|
|
508
|
+
// =============================================================================
|
|
509
|
+
|
|
510
|
+
Tensor<float> Protophone::forward(const std::vector<int64_t>& tokens) {
|
|
511
|
+
seq_len_ = tokens.size();
|
|
512
|
+
if (seq_len_ == 0) {
|
|
513
|
+
return Tensor<float>({0, NUM_PHONEMES});
|
|
514
|
+
}
|
|
515
|
+
up_len_ = 2 * seq_len_;
|
|
516
|
+
|
|
517
|
+
embed(tokens);
|
|
518
|
+
multi_kernel_conv_glu();
|
|
519
|
+
kernel_mixer();
|
|
520
|
+
upsample_linear();
|
|
521
|
+
shift_mlp();
|
|
522
|
+
return ctc_projection();
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
} // namespace phonemis::protophone
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "tensor.h"
|
|
4
|
+
#include "types.h"
|
|
5
|
+
#include <fstream>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
namespace phonemis::protophone {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* High-performance C++ implementation of the Protophone CTC model.
|
|
13
|
+
*
|
|
14
|
+
* The model is always evaluated for a single sequence (batch size 1), matching
|
|
15
|
+
* the runner which phonemizes one word at a time. The forward pass is split
|
|
16
|
+
* into a handful of fused, SIMD-accelerated stages (see protophone.cpp).
|
|
17
|
+
*
|
|
18
|
+
* Large scratch buffers are kept as members and only ever grow, so repeated
|
|
19
|
+
* calls to forward() do not reallocate once a steady-state sequence length is
|
|
20
|
+
* reached.
|
|
21
|
+
*/
|
|
22
|
+
class Protophone {
|
|
23
|
+
public:
|
|
24
|
+
explicit Protophone(const std::string& model_path);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Implements forward pass of the Protophone model.
|
|
28
|
+
* @param tokens input tokens for a single word.
|
|
29
|
+
* @return logits of shape (2 * tokens.size(), NUM_PHONEMES).
|
|
30
|
+
*/
|
|
31
|
+
Tensor<float> forward(const std::vector<int64_t>& tokens);
|
|
32
|
+
|
|
33
|
+
protected:
|
|
34
|
+
// ---- Weight loading -------------------------------------------------------
|
|
35
|
+
void load_weights(const std::string& model_path);
|
|
36
|
+
Tensor<float> read_tensor(std::ifstream& f, const std::string& name);
|
|
37
|
+
|
|
38
|
+
// ---- Inference stages (operate on the member scratch buffers) -------------
|
|
39
|
+
void embed(const std::vector<int64_t>& tokens); // -> emb_padded_
|
|
40
|
+
void multi_kernel_conv_glu(); // emb_padded_ -> glu_
|
|
41
|
+
void kernel_mixer(); // glu_ -> mixed_
|
|
42
|
+
void upsample_linear(); // mixed_ -> shift_a_
|
|
43
|
+
void shift_mlp(); // shift_a_/shift_b_ ping-pong
|
|
44
|
+
Tensor<float> ctc_projection(); // shift_a_ -> logits
|
|
45
|
+
|
|
46
|
+
// ---- Model weights --------------------------------------------------------
|
|
47
|
+
Tensor<float> embedding_;
|
|
48
|
+
|
|
49
|
+
// Multi-kernel convolutions. Weights are repacked at load time from the
|
|
50
|
+
// PyTorch [out_ch, in_ch, k] layout to [out_ch, k, in_ch] so that a single
|
|
51
|
+
// convolution output is a contiguous dot product over k * EMBEDDING_DIM.
|
|
52
|
+
Weights<float> conv3_;
|
|
53
|
+
Weights<float> conv5_;
|
|
54
|
+
Weights<float> conv7_;
|
|
55
|
+
|
|
56
|
+
// Kernel mixer (linear 3712 -> 256).
|
|
57
|
+
Weights<float> mixer_;
|
|
58
|
+
|
|
59
|
+
// ShiftMLP (four linear 256 -> 256 layers, dilations 1/2/4/8).
|
|
60
|
+
std::vector<Weights<float>> shift_mlp_;
|
|
61
|
+
|
|
62
|
+
// CTC projection (linear 256 -> 116).
|
|
63
|
+
Weights<float> ctc_proj_;
|
|
64
|
+
|
|
65
|
+
// ---- Scratch buffers (grow-only, reused across forward() calls) -----------
|
|
66
|
+
using Buffer = std::vector<float, xsimd::default_allocator<float>>;
|
|
67
|
+
|
|
68
|
+
size_t embed_dim_ = 0; // EMBEDDING_DIM: read from the embedding weight shape
|
|
69
|
+
size_t seq_len_ = 0; // S: number of input tokens
|
|
70
|
+
size_t up_len_ = 0; // T = 2 * S: upsampled length
|
|
71
|
+
|
|
72
|
+
Buffer emb_padded_; // (S + 2*MAX_PAD) x embed_dim_, zero-padded borders
|
|
73
|
+
Buffer glu_; // S x (total_K * F)
|
|
74
|
+
Buffer mixed_; // S x L
|
|
75
|
+
Buffer shift_a_; // T x L (ping)
|
|
76
|
+
Buffer shift_b_; // T x L (pong)
|
|
77
|
+
Buffer shifted_; // L: shifted feature vector for one ShiftLinear step
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
} // namespace phonemis::protophone
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "numeric.h"
|
|
4
|
+
#include "tensor_utils.h"
|
|
5
|
+
#include "tensor_view.h"
|
|
6
|
+
#include <third-party/xsimd/xsimd.hpp>
|
|
7
|
+
|
|
8
|
+
#include <algorithm>
|
|
9
|
+
#include <numeric>
|
|
10
|
+
#include <vector>
|
|
11
|
+
|
|
12
|
+
namespace phonemis::protophone {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A multidimensional tensor class template.
|
|
16
|
+
* Stores data in a linearized std::vector with XSIMD-compatible alignment.
|
|
17
|
+
*/
|
|
18
|
+
template <typename T>
|
|
19
|
+
class Tensor {
|
|
20
|
+
public:
|
|
21
|
+
explicit Tensor(std::vector<size_t> shape)
|
|
22
|
+
: shape_(std::move(shape)) {
|
|
23
|
+
strides_ = utils::compute_strides(shape_);
|
|
24
|
+
data_.resize(size(), static_cast<T>(0));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
explicit Tensor(std::vector<size_t> shape, const T* data_ptr)
|
|
28
|
+
: shape_(std::move(shape)) {
|
|
29
|
+
strides_ = utils::compute_strides(shape_);
|
|
30
|
+
data_.assign(data_ptr, data_ptr + size());
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
explicit Tensor(std::vector<size_t> shape, const T* data_ptr, std::vector<size_t> strides)
|
|
34
|
+
: shape_(std::move(shape)), strides_(std::move(strides)) {
|
|
35
|
+
data_.assign(data_ptr, data_ptr + size());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
explicit Tensor(const TensorView<T>& view)
|
|
39
|
+
: shape_(view.shape()), strides_(view.strides()) {
|
|
40
|
+
data_.assign(view.data() + view.offset(), view.data() + view.offset() + size());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Returns a non-owning view of the tensor.
|
|
45
|
+
*/
|
|
46
|
+
TensorView<T> view() {
|
|
47
|
+
return TensorView<T>(data_.data(), shape_, strides_);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Returns a non-owning view of the tensor (const version).
|
|
52
|
+
*/
|
|
53
|
+
TensorView<const T> view() const {
|
|
54
|
+
return TensorView<const T>(data_.data(), shape_, strides_);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Simple accessors
|
|
58
|
+
const std::vector<size_t>& shape() const { return shape_; }
|
|
59
|
+
const std::vector<size_t>& strides() const { return strides_; }
|
|
60
|
+
size_t size() const { return !shape_.empty() ? numeric::product(shape_) : 0; }
|
|
61
|
+
const std::vector<T, xsimd::default_allocator<T>>& data() const { return data_; }
|
|
62
|
+
|
|
63
|
+
private:
|
|
64
|
+
// Friends declarations
|
|
65
|
+
template <typename U>
|
|
66
|
+
friend void utils::repack(Tensor<U>& tensor);
|
|
67
|
+
|
|
68
|
+
// Tensor data
|
|
69
|
+
std::vector<T, xsimd::default_allocator<T>> data_;
|
|
70
|
+
|
|
71
|
+
// Tensor metadata
|
|
72
|
+
std::vector<size_t> shape_;
|
|
73
|
+
std::vector<size_t> strides_;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
} // namespace phonemis::protophone
|