Commit ยท
3d52f4f
0
Parent(s):
genmai 1.0.0
Browse files- .gitattributes +35 -0
- README.md +127 -0
- config.json +36 -0
- model-coreml.zip +3 -0
- model.safetensors +3 -0
- tokenizer.json +0 -0
- tokenizer_config.json +12 -0
.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: cc-by-sa-4.0
|
| 3 |
+
language: ja
|
| 4 |
+
base_model: Miwa-Keita/zenz-v2.5-medium
|
| 5 |
+
pipeline_tag: text-generation
|
| 6 |
+
tags:
|
| 7 |
+
- japanese
|
| 8 |
+
- input-method
|
| 9 |
+
- kana-kanji-conversion
|
| 10 |
+
---
|
| 11 |
+
# genmai-310M
|
| 12 |
+
|
| 13 |
+
A Japanese **kana-kanji conversion** model: it converts a reading (katakana) into Japanese text, optionally
|
| 14 |
+
conditioned on the text before the cursor. It is the AI converter of the macOS input method
|
| 15 |
+
[genmai](https://github.com/subdiox/genmai-ime), which runs it on device with Core ML (`model-coreml.zip`).
|
| 16 |
+
|
| 17 |
+
- Architecture: GPT-2, character-level vocabulary, 24 layers, 1024 hidden, 310M parameters
|
| 18 |
+
- Smaller variant (90M, distilled from this model, about twice as fast): [subdiox/genmai-90M](https://huggingface.co/subdiox/genmai-90M)
|
| 19 |
+
- Base model: [Miwa-Keita/zenz-v2.5-medium](https://huggingface.co/Miwa-Keita/zenz-v2.5-medium) (CC BY-SA 4.0)
|
| 20 |
+
|
| 21 |
+
## Files
|
| 22 |
+
|
| 23 |
+
Releases are git tags (`v1.0.0`); use a tag to pin a version. `main` is the latest release.
|
| 24 |
+
|
| 25 |
+
| file | contents |
|
| 26 |
+
|---|---|
|
| 27 |
+
| `model.safetensors` | fp32 weights in the Hugging Face GPT-2 layout (1.2 GB), for transformers |
|
| 28 |
+
| `config.json` | GPT-2 config; the prompt format is recorded as `"genmai_prompt_format": "zenzlc"` |
|
| 29 |
+
| `tokenizer.json`, `tokenizer_config.json` | the tokenizer |
|
| 30 |
+
| `model-coreml.zip` | what the genmai input method runs: the model as stateful Core ML packages for the Apple Neural Engine (283 MB; see below): `genmai_0.mlpackage` (layers 0โ11) and `genmai_1.mlpackage` (layers 12โ23 and the head), int8 weights, and `genmai_coreml.json` (static shapes: `format` `genmai-coreml-1`, `prompt_slots` 256, `output_steps` 64, `rows` 5, `prefill_chunk` 32, `chunks` 2) |
|
| 31 |
+
|
| 32 |
+
```python
|
| 33 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 34 |
+
m = AutoModelForCausalLM.from_pretrained("subdiox/genmai-310M", revision="v1.0.0")
|
| 35 |
+
tok = AutoTokenizer.from_pretrained("subdiox/genmai-310M", revision="v1.0.0")
|
| 36 |
+
x = tok("<s>\uee00" + "ใใใใใฌใคใฟใคใฉใทใค" + "\uee01", return_tensors="pt", add_special_tokens=False)
|
| 37 |
+
y = m.generate(**x, num_beams=5, num_return_sequences=5, length_penalty=0.0, max_new_tokens=64)
|
| 38 |
+
print([tok.decode(s[x.input_ids.shape[1]:], skip_special_tokens=True) for s in y]) # ๆฏใฏๆญฏใ็ใใใใ, ...
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
Rank beams by the plain sum of log-probabilities (`length_penalty=0.0`): with transformers' default length
|
| 42 |
+
normalisation, long degenerate outputs such as ใใใใใฌใคใฟใคใใใ can win.
|
| 43 |
+
|
| 44 |
+
## Prompt format (`zenzlc`)
|
| 45 |
+
|
| 46 |
+
Left context first (up to the last 500 characters), then the reading, then the output:
|
| 47 |
+
|
| 48 |
+
```
|
| 49 |
+
<s>[U+EE02]{left context}[U+EE00]{reading in katakana}[U+EE01]{output}</s>
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
`[U+EE0x]` are the private-use marker characters U+EE02 (context), U+EE00 (input) and U+EE01 (output).
|
| 53 |
+
Without context the `[U+EE02]{left context}` part is omitted. Spaces are written as U+3000 and newlines are
|
| 54 |
+
removed. `config.json` records the format name (`genmai_prompt_format`). Decode with beam search (genmai uses 5 beams) and stop at EOS;
|
| 55 |
+
long readings are split at ใใ into chunks of at most 40 characters, each decoded after the previous output.
|
| 56 |
+
|
| 57 |
+
## Core ML (Apple Neural Engine)
|
| 58 |
+
|
| 59 |
+
`model-coreml.zip` holds the same model converted with coremltools 9 (macOS 15 / iOS 18 or later) for the genmai
|
| 60 |
+
input method's Core ML decoder. A package with all 24 layers does not load on the Neural Engine, so the model is
|
| 61 |
+
split into two packages; each has two functions that share the package's states (per layer, keys and values in
|
| 62 |
+
fp16):
|
| 63 |
+
|
| 64 |
+
- `prefill`: 32 prompt tokens written to prompt slots `start ..< start + 32` (`mask` (32, 256) additive). Inputs of
|
| 65 |
+
`genmai_0`: `ids`, `pos` (1, 32) int32, `start` (1,) int32, `mask`; of `genmai_1`: `hidden` (1, 32, 1024) fp16 (the
|
| 66 |
+
output of `genmai_0`), `start`, `mask`. Outputs: `hidden` (`genmai_0`), `logp` (32, 6000) (`genmai_1`).
|
| 67 |
+
- `decode`: one token for each of 5 beams. Inputs of `genmai_0`: `tok` (5, 1) int32, `pos` (1,) int32; of
|
| 68 |
+
`genmai_1`: `hidden` (5, 1, 1024) fp16; both: `wsel` (320, 5) / `keep` (320, 1), `pmask` (1, 256) / `smask` (5, 320)
|
| 69 |
+
fp16 additive. Beam r's token of step t is stored at output slot t ยท 5 + r (`wsel` is the one-hot placement, `keep`
|
| 70 |
+
= 1 โ its row sums); each beam attends to the prompt slots in `pmask` and to its ancestors' slots in `smask`.
|
| 71 |
+
|
| 72 |
+
The Neural Engine computes in fp16 (at most 65504), which this model exceeds: its residual stream reaches about 81k
|
| 73 |
+
and one attention head of the second layer has logits up to about 500k. The packages are reparametrized exactly to stay in
|
| 74 |
+
range: the residual stream is scaled by 0.25 (embeddings and the attention / MLP output projections ร 0.25, layer
|
| 75 |
+
norm epsilon ร 1/16; the head uses the unscaled embeddings), and attention logits are computed / 256 (folded into the
|
| 76 |
+
query weights), the row maximum subtracted and the result ร 256 before the softmax. Linear weights are int8
|
| 77 |
+
(symmetric, per channel), the rest fp16. The conversion script is `Tools/coreml/genmai_coreml.py` of
|
| 78 |
+
[genmai-ime](https://github.com/subdiox/genmai-ime) (`--chunks 2 --residual-scale 0.25 --score-scale 256`).
|
| 79 |
+
|
| 80 |
+
On an M4 Pro (5 beams): top-1 accuracy (exact) 94.1 / 93.0 / 78.6 % on everyday sentences / AJIMEE / hard sentences
|
| 81 |
+
(the weights in 8 bits on the GPU: 93.1 / 92.5 / 78.6 %, top-1 identical on 96โ98.5 % of the items); process
|
| 82 |
+
footprint 80โ140 MB; a whole everyday sentence converts in a median 113 ms, the input method's conversion key (which
|
| 83 |
+
converts while you type) answers in a median 30 / 39 ms (everyday sentences / AJIMEE). The first load compiles the model for the Neural Engine
|
| 84 |
+
(about 20 s; macOS caches the result).
|
| 85 |
+
|
| 86 |
+
## Training
|
| 87 |
+
|
| 88 |
+
Fine-tuned from zenz-v2.5-medium in several stages on (reading, text) pairs:
|
| 89 |
+
|
| 90 |
+
1. ~6M automatically read sentences from Japanese Wikipedia, FineWeb-2 (Japanese), Aozora Bunko and Diet
|
| 91 |
+
minutes (readings by UniDic with corrections learned from reviewed samples);
|
| 92 |
+
2. long left context (up to 500 characters);
|
| 93 |
+
3. reading/surface pairs of the Mozc dictionary (dictionary_oss) and sentences containing rare dictionary words;
|
| 94 |
+
4. curated data: hand-checked items, synthetic sentences and homophone sets generated with Claude, and
|
| 95 |
+
LLM-judged corrections, with replay of the earlier data;
|
| 96 |
+
5. training with an auxiliary next-character language-model loss on the real text before the cursor (so the
|
| 97 |
+
model learns how words are used in running text, not only the conversions).
|
| 98 |
+
|
| 99 |
+
The release is a single model after one more round of stage 5 on ~1M further pairs.
|
| 100 |
+
|
| 101 |
+
## Evaluation
|
| 102 |
+
|
| 103 |
+
Top-1 accuracy, beam size 5, bf16; candidates whose reading does not match the input are dropped. AJIMEE, everyday
|
| 104 |
+
sentences and ime_v1 dev are judged leniently (orthographic variants accepted); homophones = word-level accuracy
|
| 105 |
+
on held-out homophone sentences; hard = 28 sentences written to stress an IME (exact match up to orthography).
|
| 106 |
+
|
| 107 |
+
| set | genmai-310M (bf16) | Zenzai (zenz-v3.2-small, azooKey settings) |
|
| 108 |
+
|---|---|---|
|
| 109 |
+
| AJIMEE-Bench (200) | 95.0 % | 85.5 % |
|
| 110 |
+
| everyday sentences (101) | 98.0 % | 97.0 % |
|
| 111 |
+
| ime_v1 dev (544) | 93.6 % | โ |
|
| 112 |
+
| homophone sentences (1,607) | 93.1 % | โ |
|
| 113 |
+
| average of the four | 94.9 % | โ |
|
| 114 |
+
| hard IME sentences (28) | 22 / 28 | โ |
|
| 115 |
+
|
| 116 |
+
## Limitations
|
| 117 |
+
|
| 118 |
+
- Readings that repeat one sound (ใใใใฎใใใใใใใใงใใใใใ) tend to map every occurrence to the same word
|
| 119 |
+
or drop part of the reading.
|
| 120 |
+
- Rare proper nouns and fine homophone distinctions (็นๅพด/็น้ท, ่ฟฝๅ/่ฟฝๆฑ) are still error-prone.
|
| 121 |
+
- The model copies the left context strongly: a wrong conversion earlier in the context can be repeated.
|
| 122 |
+
|
| 123 |
+
## License and attribution
|
| 124 |
+
|
| 125 |
+
CC BY-SA 4.0. The training data include Wikipedia (CC BY-SA), FineWeb-2 (ODC-By), Aozora Bunko, the National
|
| 126 |
+
Diet minutes, and the Mozc dictionary (BSD-3-Clause, Copyright Google Inc.; contains data derived from IPAdic,
|
| 127 |
+
Copyright Nara Institute of Science and Technology).
|
config.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"activation_function": "gelu_pytorch_tanh",
|
| 3 |
+
"add_cross_attention": false,
|
| 4 |
+
"architectures": [
|
| 5 |
+
"GPT2LMHeadModel"
|
| 6 |
+
],
|
| 7 |
+
"attn_pdrop": 0.0,
|
| 8 |
+
"bos_token_id": 2,
|
| 9 |
+
"dtype": "float32",
|
| 10 |
+
"embd_pdrop": 0.0,
|
| 11 |
+
"eos_token_id": 3,
|
| 12 |
+
"initializer_range": 0.02,
|
| 13 |
+
"layer_norm_epsilon": 1e-05,
|
| 14 |
+
"model_type": "gpt2",
|
| 15 |
+
"n_ctx": 1024,
|
| 16 |
+
"n_embd": 1024,
|
| 17 |
+
"n_head": 16,
|
| 18 |
+
"n_inner": null,
|
| 19 |
+
"n_layer": 24,
|
| 20 |
+
"n_positions": 1024,
|
| 21 |
+
"pad_token_id": 1,
|
| 22 |
+
"reorder_and_upcast_attn": false,
|
| 23 |
+
"resid_pdrop": 0.0,
|
| 24 |
+
"scale_attn_by_inverse_layer_idx": false,
|
| 25 |
+
"scale_attn_weights": true,
|
| 26 |
+
"summary_activation": null,
|
| 27 |
+
"summary_first_dropout": 0.1,
|
| 28 |
+
"summary_proj_to_labels": true,
|
| 29 |
+
"summary_type": "cls_index",
|
| 30 |
+
"summary_use_proj": true,
|
| 31 |
+
"tie_word_embeddings": true,
|
| 32 |
+
"transformers_version": "5.20.0",
|
| 33 |
+
"use_cache": false,
|
| 34 |
+
"vocab_size": 6000,
|
| 35 |
+
"genmai_prompt_format": "zenzlc"
|
| 36 |
+
}
|
model-coreml.zip
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:da2a6e1a9fbf0729c84b8497462ae4ffaf8b2dd2b74c808f3de971b5643ef3ff
|
| 3 |
+
size 282924021
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d44679bed94faf1e8baa4edf7a4d0bc57c5664d8094afb7688feed98fc0f279b
|
| 3 |
+
size 1238046208
|
tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"add_prefix_space": false,
|
| 3 |
+
"backend": "tokenizers",
|
| 4 |
+
"bos_token": "<s>",
|
| 5 |
+
"clean_up_tokenization_spaces": true,
|
| 6 |
+
"eos_token": "</s>",
|
| 7 |
+
"errors": "replace",
|
| 8 |
+
"model_max_length": 1000000000000000019884624838656,
|
| 9 |
+
"pad_token": "[PAD]",
|
| 10 |
+
"tokenizer_class": "GPT2Tokenizer",
|
| 11 |
+
"unk_token": "[UNK]"
|
| 12 |
+
}
|