Moonshine Encoder (Speech-to-Text)
skainet-transformers-inference-moonshine provides the Moonshine-tiny speech-to-text
encoder built entirely in the SKaiNET NN DSL. Unlike the GGUF/eager LLM runtimes, this model
is authored as a graph you compile: DSL β StableHLO β IREE, so the same definition runs on a
CPU backend or a hardware NPU. It was first published in 0.34.0; 0.34.1 layer-qualifies
its parameter names (see below).
|
Encoder only β for now. Moonshine is an encoder-decoder (seq2seq) model, like Whisper: an
encoder turns audio into a memory tensor, and an autoregressive decoder emits text using
self-attention (KV-cached) plus cross-attention into that memory. This module currently
implements only the encoder β the compute-heavy half and the one that carried the hard NPU
compilation work (bidirectional attention, partial RoPE, bf16 LayerNorm). The decoder is not yet
authored in the DSL: in the SL2610 demo it runs from prebuilt vendor vmfbs
( |
Coordinates
dependencies {
implementation(platform("sk.ainet.transformers:skainet-transformers-bom:0.34.1"))
implementation("sk.ainet.transformers:skainet-transformers-inference-moonshine")
}
API
public fun <T : DType, V> moonshineEncoder(
cfg: MoonshineConfig,
dtype: KClass<T>,
): Module<T, V>
Build it with BF16 so the DSLβStableHLO export keeps bf16 weights at the matmul β the
Torq NPU requirement (fp32 weights crash the Torq compiler’s getWeightMemoryFormat). The
input is the conv-frontend output [batch, frames, dim]; the output is the encoder memory
[batch, frames, dim] for a decoder’s cross-attention.
MoonshineConfig (moonshine-tiny defaults)
| Field | Default | Notes |
|---|---|---|
|
|
model width ( |
|
|
pre-norm transformer layers |
|
|
attention heads |
|
|
per-head width |
|
|
GELU MLP hidden (4 Γ dim) |
|
|
encoder sequence length after the conv frontend |
|
|
rotate 32 of 36 head dims; the trailing 4 pass through |
|
|
RoPE base |
Architecture
Each layer is pre-norm: x + Attn(LN(x)) then x + MLP(LN(x)), with
-
non-causal RoPE self-attention (bidirectional, no bias). Moonshine uses interleaved (adjacent-pair) RoPE with partial rotary β only
headDim Γ partialRotaryFactor = 32of the 36 head dims are rotated, andinv_freqis computed over the rotary dim (32), not the full head dim. -
a plain GELU MLP (
fc1 β GELU β fc2), both projections biased.
A final LayerNorm produces the encoder memory.
Compilation path
The emitted StableHLO is portable β it names no backend. Hardware-specific optimizations
(e.g. the Synaptics Torq attention/FFN tiling and compile flags) plug in from outside core via
the TargetOptimizer registry, so the model definition stays target-agnostic:
moonshineEncoder() β tape β ComputeGraph β DtypeForwardPropagation(bf16) β StableHLO
β
(vendor plugin adds target passes) β iree-compile β vmfb
See the SKaiNET Embedded docs (sl2610-function-calling) for an end-to-end example that
self-compiles this encoder from the DSL and runs it on the Synaptics SL2610 NPU.
|
Validation status. This encoder is proven end-to-end, not just structurally emitted: on
|
Parameter names
As of 0.34.1 every parameter is uniquely layer-qualified, so by-name weight loading can tell the layers apart:
enc.$layer.attn_norm.{weight,bias}
enc.$layer.attn.{q,k,v,o}_proj.weight
enc.$layer.ffn_norm.{weight,bias}
enc.$layer.ffn_up.{weight,bias} # fc1
enc.$layer.ffn_down.{weight,bias} # fc2
enc_out_norm.{weight,bias} # final norm
|
In 0.34.0 the attention/LayerNorm names were not layer-qualified ( |