Yet another kana-kanji-converter on IBus, written in Rust.
統計的かな漢字変換による日本語IMEです。 Rust で書いています。
現在、開発途中のプロダクトです。非互換の変更が予告なくはいります
- akaza-default-model - デフォルト言語モデル
- jawiki-kana-kanji-dict - Wikipedia ベース SKK 辞書
いじりやすくて ある程度 UIが使いやすいかな漢字変換があったら面白いなと思ったので作ってみています。 「いじりやすくて」というのはつまり、Hack-able であるという意味です。
モデルデータを自分で生成できて、特定の企業に依存しない自由なかな漢字変換エンジンを作りたい。
- Rust で実装: UI/Logic をすべて Rust で書いてあるので、拡張が容易です
- 統計的かな漢字変換: 2gram 言語モデルを採用
- 言語モデルの生成元は日本語 Wikipedia と青空文庫です
- 形態素解析器 Vibrato で分析した結果をもとに構築
- 利用者の環境で 1 から言語モデルを再生成することが可能です
- 学習機能: ユーザー環境で、利用者の変換結果を学習します (unigram, bigram の頻度を学習)
- GUI 設定ツール: GTK4 ベースの設定ツールを提供
akaza-conf: キーマップ、辞書、モデルなどの設定akaza-dict: ユーザー辞書の編集
- SKK 辞書対応: SKK 形式の辞書ファイルを複数読み込み可能
Akaza は 単語 bigram モデルに基づく統計的かな漢字変換 を行っています。 変換は大きく 3 つのフェーズで構成されます。
入力されたかな文字列を、辞書に登録されている単語の読みに基づいて分割候補を列挙します。
- MARISA Trie に格納されたシステム辞書と、Cedarwood Trie に格納されたユーザー辞書を用いて共通接頭辞検索を行い、可能な単語境界をすべて列挙します
- BFS(幅優先探索)で全分割パターンを探索し、
{終了位置 → [読み候補]}のマップを生成します - 数字、未知文字(辞書に存在しない文字)の自動認識も行います
例: "わたしのなまえ" → {6: ["わた", "わたし"], 9: ["し", "の"], ...}
セグメンテーション結果をもとに、各位置での変換候補を含むラティスグラフを構築します。
- 各読みに対して、システム辞書・ユーザー辞書から漢字候補を検索します
- 辞書に存在しない読みには、ひらがな・カタカナのフォールバック候補を自動生成します
- 数字の漢数字変換、日付・時刻の動的変換なども候補に追加されます
- 各ノードは
(表層形, 読み, 単語ID, ユニグラムコスト)を保持します
例: 位置 0〜9 のノード:
[BOS] → [私/わたし, わたし/わたし, ワタシ/わたし, ...] → ... → [EOS]
ラティスグラフ上で ビタビアルゴリズム(動的計画法)を用いて、最もコストの低い変換候補列を求めます。
コストの構成要素:
| コスト | 説明 | 算出方法 |
|---|---|---|
| ユニグラムコスト | 単語の出現しやすさ | -log10(P(word)) (加法スムージング適用) |
| バイグラムコスト | 単語間の遷移しやすさ | -log10(P(word_n | word_{n-1})) |
- 前向きパス: BOS(文頭)から EOS(文末)に向かって、各ノードの累積最小コストと最良の前ノードを記録します
- 後ろ向きパス: EOS から BOS へ最良前ノードをたどり、最適な変換結果を取得します
- ユーザーの学習データがある場合、システムモデルより優先して参照されます
辞書に登録しきれない数字などの変換は、動的変換マーカーの仕組みで処理しています。
- Segmenter: 正規表現
^(?:0|[1-9][0-9]*)(\.[0-9]*)?で数字列を検出し、1 トークンとして切り出す - GraphBuilder: 数字トークンに対して、surface を
"(*(*(NUMBER-KANSUJI"というマーカー文字列にした WordNode をラティスに追加する - GraphResolver: 通常通りビタビ探索を行い、Candidate を生成(surface はマーカーのまま)
- 表示時:
Candidate::surface_with_dynamic()が呼ばれ、int2kanji()で漢数字に変換される
| 入力 | 漢数字変換 |
|---|---|
0 |
零 |
10 |
十 |
365 |
三百六十五 |
10000 |
一万 |
- 辞書に数字を登録しない: 無限にある数値パターンを辞書でカバーするのは不可能なため、正規表現で検出して動的に変換する
- 遅延評価: マーカー文字列をラティスに入れておき、実際の変換は表示時に行う。これにより、ラティス構築・ビタビ探索のロジックを数字のために特殊化する必要がない
- 拡張可能:
"(*(*(..."マーカーの仕組みは数字以外(日付・時刻など)にも利用されている
┌─────────────────┐
│ 入力(かな) │
└────────┬────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│システム辞書│ │ユーザー辞書│ │ SKK 辞書 │
│(MARISA) │ │(Cedarwood) │ │(複数読込) │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
└───────────┬───┘───────────────┘
▼
┌────────────────┐
│ ラティス構築 │
└───────┬────────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
┌───────────┐ ┌────────┐ ┌────────────────┐
│ unigram │ │bigram │ │ユーザー学習 │
│ .model │ │.model │ │(unigram/bigram)│
│(MARISA) │ │(MARISA)│ │(.txt) │
└─────┬─────┘ └───┬────┘ └───────┬────────┘
└────────┬───┘──────────────┘
▼
┌─────────────────┐
│ ビタビ最適経路 │
└────────┬────────┘
▼
┌─────────────────┐
│ 変換結果出力 │
└─────────────────┘
システム辞書 (SKK-JISYO.akaza): 日本語 Wikipedia・青空文庫から抽出した読み→漢字の対応表。MARISA Trie で格納。SKK-JISYO.L に含まれない語彙を補完する役割で、SKK-JISYO.L などと併用することを想定しています。
言語モデル:
unigram.model: 各単語の出現コスト。MARISA Trie に(単語ID 24bit, スコア f32)を格納。bigram.model: 単語間の遷移コスト。MARISA Trie に(単語ID1 3byte + 単語ID2 3byte + スコア f16)を格納。スコアは-log10(確率)で表現。- 学習コーパスは日本語 Wikipedia と青空文庫を Vibrato で形態素解析して構築。
- 加法スムージング(α=0.00001)でゼロ頻度問題に対応。
ユーザー学習データ (~/.local/share/akaza/):
unigram.v1.txt/bigram.v1.txt: ユーザーが確定した変換結果の頻度統計SKK-JISYO.user: ユーザー定義の読み→漢字辞書- 変換確定時に自動更新され、次回変換時にシステムモデルより優先されます
デフォルトモデルは default-model/ ディレクトリで構築されます。日本語 Wikipedia・青空文庫・CC-100 をトークン化して n-gram 統計を生成し(corpus-stats/)、手作業コーパスで補正してモデルとシステム辞書を出力します。
詳細なパイプラインは default-model/README.md を参照してください。
言語モデルの構築時およびランタイムの LM lookup 時に、数字+接尾辞のトークン(例: 1匹, 2019年)を <NUM> に正規化してカウントを集約し、数字+助数詞パターン全般の変換精度を向上させています。
正規化ルールの詳細は corpus-stats/README.md を参照してください。
誤変換の原因に応じて、適切な調整方法があります。
corpus/*.txt(bigram スコア調整): 同音異義語の文脈判別、分節解析の補強、誤候補の抑制。コーパスに書かれた単語はシステム辞書にも自動登録されます。mecab-user-dict.csv(Vibrato トークン化の修正): Vibrato が未知語として扱う単語や分割を誤る複合語を登録。訓練時のトークン化に影響し、IME の分節解析には間接的に影響します。dict/SKK-JISYO.akaza(システム辞書の補完): SKK-JISYO.L に含まれない新語・固有名詞・専門用語を追加。
詳細な調整ガイドは default-model/README.md を参照してください。
Akaza は単語 bigram モデルを採用しているため、直前の 1 単語しか文脈として参照できない という原理的な制約があります。
bigram で対応できる例:
- 「板が厚い」vs「お湯が熱い」 — 直前の名詞で同音異義語を区別可能
bigram では対応が困難な例:
- 「夏は暑い」vs「この板は厚い」 — 直前の助詞「は」が同じため区別不能。共起情報(離れた単語との関連性)が必要
- 文末の意志形「だらだらしよう」→「使用」に誤変換 — 直前の語がさまざまで bigram では汎用的に抑制困難
- 「猫を飼う」→「買う」に誤変換 — 直前の助詞「を」が同じため区別不能
BOS(文頭)と EOS(文末)に word_id を付与し、bigram モデルに含めています。これにより、文頭に来やすい単語(「私は」「今日は」など)や文末に来やすい単語の情報が変換精度の向上に活用されます。古いモデルファイル(BOS/EOS エントリなし)では従来通りデフォルトコストにフォールバックします。
隣接 bigram に加えて、1語飛ばした単語ペア (w_{i-2}, w_i) の共起頻度を Viterbi DP に統合しています。これにより、「夏は暑い」と「板は厚い」のように助詞を挟んだ共起関係を捉え、bigram だけでは判別できない同音異義語の解消を補助します。
ビタビアルゴリズムを拡張した k-best Viterbi を実装しています。各ノードに対して上位 k 個の (cost, prev_node, prev_rank) エントリを保持し、EOS から逆方向にたどることで分節の区切り方が異なるパスを k 本列挙します。Tab キーでパスを切り替え可能です。
現在の実装では、各ノードの上位 k エントリは Vec をソートして truncate(k) する方式です。
OSS として持続可能な開発を行うため、学習データは Wikipedia と青空文庫に限定しています。無料で利用可能な GitHub Actions のリソースで処理できる分量に収めているため、大規模な商用かな漢字変換エンジンと比べるとデータ量に限りがあります。口語表現やビジネス表現のカバーが薄いという弱点があります。
以下は、上記の制約を踏まえて検討している改善案です。
現在の bigram(2単語間)から trigram(3単語間)に拡張することで、より広い文脈を考慮した変換が可能になる。
- 期待される効果: 「AはB」のように助詞を挟むパターンで、2 単語前の名詞を参照できる。
- 課題: モデルサイズの増大。bigram でも MARISA Trie で圧縮しているが、trigram ではエントリ数が大幅に増加する。スパースデータ問題も深刻化する。
Transformer ベースの軽量モデルを用いたリスコアリングにより、統計モデルでは捉えきれない長距離の文脈依存性を扱う。
- 期待される効果: 文全体の意味を考慮した変換が可能になり、bigram の原理的限界を根本的に解消できる。
- 課題: 推論速度(IME はリアルタイム応答が必要)。モデルサイズ(オンデバイスで動作する必要がある)。n-best のリスコアリングに限定すれば負荷を抑えられる可能性がある。
「一日中」(いちにちじゅう)が「一日+十」に分節されるなど、分節解析が正しい複合語を分割してしまうケースへの対応。
入力途中での変換候補の提示。入力効率の向上が期待できる。
LLM(ChatGPT、Claude 等)による日本語文の生成を活用し、口語表現・ビジネス表現・季節の挨拶など Wikipedia に出にくい表現のカバーを強化する。LLM 生成文は著作権の問題がなく Public Domain として扱える。
| 用語 | 説明 |
|---|---|
| PreComposition | 未入力状態。preedit が空で、IME がキー入力を待っている状態 |
| Composition | preedit にローマ字/ひらがなが入力されているが、まだ変換(Space)を押していない状態。サジェスト有効時は候補ポップアップが表示されることがある |
| Conversion | Space を押して変換候補が確定候補として表示されている状態。文節の選択や候補の切り替えが可能 |
| preedit | 入力中の未確定文字列。アプリケーションのカーソル位置にインラインで表示される |
| lookup table | 変換候補のポップアップウィンドウ。IBus が提供する候補一覧 UI |
| clause(文節) | 変換結果を構成する単位。例: 「今日は/いい/天気です」の各区切り |
| k-best | ビタビアルゴリズムで上位 k 個の分節パターンを列挙する手法。Tab キーで切り替え可能 |
| サジェスト | Composition 中にひらがな2文字以上入力された時点で、変換候補をポップアップ表示する機能。preedit はひらがなのまま |
| ライブ変換 | Composition 中にリアルタイムで変換結果を preedit に反映する機能。サジェストとは異なり preedit 自体が漢字に変わる |
| auxiliary text | lookup table と併せて表示される補助テキスト。選択中の文節の読みなどを表示 |
| commit(確定) | 変換結果をアプリケーションに送信し、入力を完了すること |
- ibus 1.5+
- marisa-trie (libmarisa)
- GTK 4.0+ (設定ツール用)
- Rust 1.92.0+ (stable toolchain)
- Cargo
- pkg-config
- clang
- libibus-1.0-dev
- libmarisa-dev
- libgtk-4-dev
- libgirepository1.0-dev
- OS: Linux 6.0 以上
- IBus: 1.5 以上
Ubuntu/Debian の場合:
sudo apt-get update
sudo apt-get install ibus libgirepository1.0-dev libmarisa-dev clang libibus-1.0-dev libgtk-4-dev pkg-configcurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup install stablegit clone https://github.com/akaza-im/akaza.git
cd akaza
make
sudo make installmake install により、モデルファイル(default-model/)のダウンロードとインストールも自動で行われます。
ibus restart
ibus engine akaza※ 再ログインは不要です。必要な場合は ibus restart で再起動できます。
または、IBus の設定画面から Akaza を追加してください。
インストール後、以下のコマンドで GUI 設定ツールを起動できます:
# 一般設定(キーマップ、辞書、モデルなど)
akaza-conf
# ユーザー辞書の編集
akaza-dictGUI ツールを使用すると、キーマップの選択、SKK 辞書の追加、モデルの切り替えなどが簡単に行えます。
設定ファイルは ~/.config/akaza/config.yml に保存されます。
Akaza は典型的には以下の順番で探します。
~/.local/share/akaza/keymap/{KEYMAP_NAME}.yml/usr/local/share/akaza/keymap/{KEYMAP_NAME}.yml/usr/share/akaza/keymap/{KEYMAP_NAME}.yml
このパスは、XDG ユーザーディレクトリ
の仕様に基づいています。
Akaza は Keymap を XDG_DATA_HOME と XDG_DATA_DIRS から探します。
XDG_DATA_HOME は設定していなければ ~/.local/share/ です。XDG_DATA_DIRS は設定していなければ /usr/local/share:/usr/share/ です。
ローマ字かなマップも同様のパスから探します。
~/.local/share/akaza/romkan/{ROMKAN_NAME}.yml/usr/local/share/akaza/romkan/{ROMKAN_NAME}.yml/usr/share/akaza/romkan/{ROMKAN_NAME}.yml
設定変更は akaza-conf の GUI で行うことを推奨します。
Model は複数のファイルからなります:
unigram.modelbigram.modelSKK-JISYO.akaza
以下のパスから読み込まれます:
~/.local/share/akaza/model/{MODEL_NAME}/unigram.model~/.local/share/akaza/model/{MODEL_NAME}/bigram.model~/.local/share/akaza/model/{MODEL_NAME}/SKK-JISYO.akaza
keymap, romkan と同様に、XDG_DATA_DIRS からも読むことができます。
流行り言葉が入力できない場合、jawiki-kana-kanji-dict の利用を検討してください。 Wikipedia から自動的に抽出されたデータを元に SKK 辞書を作成しています。 Github Actions で自動的に実行されているため、常に新鮮です。
一方で、自動抽出しているために変なワードも入っています。変なワードが登録されていることに気づいたら、github issues で報告してください。
必要な SKK 辞書を読み込んでください。
GUI での設定(推奨):
akaza-confを起動- 「辞書」タブから SKK 辞書ファイルを追加
手動での設定:
~/.config/akaza/config.yml の skk_dicts セクションに辞書パスを追加してください。
利用可能な SKK 辞書: https://skk-dev.github.io/dict/
このリポジトリは以下のクレートで構成されています:
| クレート | 説明 |
|---|---|
| ibus-akaza | IBus エンジン本体 |
| libakaza | かな漢字変換エンジンのコアロジック |
| akaza-conf | GUI 設定ツール (GTK4) |
| akaza-dict | GUI 辞書編集ツール (GTK4) |
| akaza-data | 開発者向けツール(変換テスト、言語モデル生成、精度評価など) |
| ibus-sys | IBus の Rust バインディング |
akaza-data は開発者向けのツールで、CLI からかな漢字変換のテストや言語モデルの生成ができます。
# かな漢字変換を実行
akaza-data check きょうはいいてんきですね
# => 今日/は/いい/天気/です/ね
# JSON 形式で複数候補を表示
akaza-data check --format json --candidates 3 きょうはいいてんきですね
# ユーザー学習データを使用
akaza-data check --user-data きょうはいいてんきですね
# 変換精度を評価
akaza-data evaluate --corpus corpus.txt --model-dir /path/to/model詳細は akaza-data --help または akaza-data/README.md を参照してください。
開発中は dev-install プロファイル(opt-level=2, codegen-units=16, lto=false)を使うことで、release ビルドより大幅に高速にビルドできます。
# 初回のみ: debug 用 xml をインストール(ibus が target/ のバイナリを直接起動する)
sudo make dev-setup
# 以降の開発サイクル: ビルド + ibus restart のみ(install 不要)
make dev-rundev-setup を実行すると、IBus の component xml がビルドディレクトリのバイナリを指すようになるため、sudo make install でバイナリをコピーする必要がなくなります。
注意:
sudo make installを実行するとtarget/内のファイルが root 所有になり、以降のビルドで権限エラーが発生します。ビルドとインストールは必ず分けて実行してください:make # ユーザー権限でビルド sudo make install # root 権限でインストール(ビルドは走らない)
# すべてのクレートをビルド
cargo build --workspace
# リリースビルド
cargo build --workspace --release
# 開発用ビルド(高速)
make dev
# テスト実行
cargo test --workspacecargo fmt --allcargo clippy -- -D warningsMIT License
- ibus-uniemoji を参考に初期の実装を行いました
- 日本語入力を支える技術 を読み込んで実装しました。この本がなかったら実装しようと思わなかったと思います
- 形態素解析器 Vibrato を使用しています