Laya-Multilingual-LiteRT / android /docs /HOST_CONTRACT.md
mlboydaisuke's picture
Super-squash branch 'main' using huggingface_hub
eae8f62
|
Raw History Blame Contribute Delete
4.61 kB

Multilingual host contract

This is the Android integration summary for the pinned multilingual Laya checkpoint convaiinnovations/laya@1c5edc17a7acd8701df6fc341c0d179f1c62c982 and upstream laya 0.3.4. The complete Python host contract and executable reference are shipment artifacts HOST_CONTRACT.md and laya_host.py in litert-community/Laya-Multilingual-LiteRT. The app uses the embedding-input graph interface below.

Tokenizer and prompt

LayaTokenizer loads the complete checkpoint BPE JSON with 256,000 vocabulary entries. It matches added tokens, replaces ASCII spaces with U+2581, applies Metaspace with always-prepend and splitting, merges by rank, and falls back to UTF-8 byte tokens. Text fragments use addSpecialTokens = false; the builder inserts CLS 2, SEP 1, and MASK 4 itself. PAD is 0 and UNK is 3. No extra Unicode normalization is applied.

Each call contains one question, with schema type choice, score, or noul. The builder preserves question and option order, encodes the literal type question: instructions prefix, and renders the upstream criteria without changing them. Options have one MASK marker followed by at most 48 text tokens. With head budget 256, an option budget below 16 triggers the exact upstream squeeze rule; the instruction slice keeps max(8, remaining budget) tokens.

The sequence is CLS + instruction + SEP + marked options + SEP + state + SEP. String state passes through; map/list state uses Python-compatible insertion order, Unicode, JSON booleans/null, comma-space and colon-space separators. Literal <mask> in text is replaced by an ASCII space. State tokens are truncated on the right to fit the selected static window; the final whole-sequence slice and marker filter follow upstream. A row that loses an option marker is rejected before inference.

Graph inputs and outputs

The app uses one serving_default signature per graph. Buffers are mapped by signature names and runtime order. All inputs and outputs below are float32; N is 256 in the UI.

Graph Direction Name Shape
Main Input inputs_embeds [1,N,768]
Main Input attention_mask [1,N]
Main Input qtype_onehot [1,3]
Main Output token_logits [1,N]
Main Output pooled_cls [1,768]
Action Input pooled_cls [1,768]
Action Input feats [1,4]
Action Output act_logits [1,2]

LayaEmbeddings maps the little-endian FP16 [256000,768] table read-only and converts gathered rows to float32. Right padding gathers token 0, including its actual vector; it does not insert an all-zero vector. Attention is 1 for real sequence positions and 0 for padding. Question-type order is choice, score, noul. The whole table's FP16 cast round-trip maximum absolute error is 0. WFP16 storage changes only fully connected weights in the main graph.

Decoder and calibration

Gather marker logits, then compute stable raw softmax. The action features are raw top-1 probability, top-1 minus top-2, normalized raw entropy using k = max(K,2) and a log floor of 1e-9, and k/255. Action probability is softmax(act_logits)[0]; it is uncalibrated.

Option temperature first uses temperature_by_options with bucket suffix 2, 3-5, 6-10, or 11+, then temperature[qtype]. Its floor is 1e-3. Calibrated loads the supplied JSON; T=1 (uncalibrated) uses identity temperatures. The calibrated UI and T=1 conversion gates are intentionally separate measurements.

Choice returns the first argmax label and ordered probabilities. Score returns the expected zero-based index, all probabilities, and the original legend. Noul returns continuous true probability. Choice/score confidence is normalized entropy confidence with a 1e-12 floor; noul confidence is max(pTrue, 1-pTrue). Values are rounded to four decimal places using Python's ties-to-even rule on the represented binary double, after intermediate math.

Executable checks

The host implementation is in app/src/main/java/com/laya/: LayaTokenizer.kt, LayaPromptBuilder.kt, LayaDecoder.kt, LayaCalibration.kt, LayaEmbeddings.kt, and LayaEngine.kt. JVM parity tests compare all captured IDs, marker positions, official and calibrated answer dictionaries, state serialization, and embedding values. Fixture layout and counts are documented in TEST_DATA.md. No JVM parity result substitutes for the on-device tokenizer and numerical gate.