Meta配布のfastText学習済みモデル(fasttext-157lang/cc.ja.300.bin)で、辞書の全単語取得(model.get_words)を行うと、UnicodeDecodeErrorが出る現象の回避方法と原因

# 記事概要と検証環境と検証対象モデル
「Python `3.11`」とPythonライブラリの「fastText `0.9.2`」で、Meta(旧Facebook)公式が配布しているfastTextの日本語事前学習モデル(`fasttext-157lang/cc.ja.300.bin`)をロードし、辞書の全単語を`model.get_words()`で取得しようとすると、文字コードに関するエラーが出てしまう現象があるので、エラー回避方法や発生原因をまとめました。間違っている部分があったら指摘大歓迎です。

&nbsp;
**検証環境**
- Python(`ver 3.11)`

- Metaが公開しているfastTextのPythonライブラリ（`ver 0.9.2`）
https://github.com/facebookresearch/fastText/tree/main/python
https://pypi.org/project/fasttext/

**検証対象の配布モデル**
- Metaが公式サイトで配布しているfastTextの事前学習モデル(Common CrawlとWikipediaで学習、157言語)の中で、日本語のもの(`fasttext-157lang/cc.ja.300.bin`)
https://fasttext.cc/docs/en/crawl-vectors.html


# エラーのサンプル(UnicodeDecodeError)

以下のサンプルのように、`fasttext-157lang/cc.ja.300.bin`をロード、`model.get_words()`か`model.words`で辞書の全単語を取得しようとすると、UnicodeDecodeError(UTF-8コーデックで文字のデコードに失敗)が発生します。

```py:sample.py
import fasttext
from fasttext.FastText import _FastText

if __name__ == "__main__":

    # Meta公式サイトからダウンロードしたモデルをロード
    # https://fasttext.cc/docs/en/crawl-vectors.html
    fasttext_model: _FastText = fasttext.load_model(
        "./fasttext-157lang/cc.ja.300.bin"
    )
    
    # ここでエラー(UnicodeDecodeError)
    model_vocab: list = fasttext_model.get_words()
    # model_vocab: list = fasttext_model.words # 上と同じ
```

```txt:実行結果
Traceback (most recent call last):
  File "c:\Qiita\sample.py", line 9, in 
<module>
    print(fasttext_model.get_words())
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Qiita\sample.py\.venv\Lib\site-packages\fasttext\FastText.py", line 
255, in get_words
    pair = self.f.getVocab(on_unicode_error)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe3 in position 0: unexpected end 
of data
```

# エラーが出る理由(無効なUTF-8文字列が原因)
fastTextのGitHubリポジトリに、「Meta公式サイトで配布されている韓国語モデル（`fasttext-157lang/cc.ko.300.bin`)と英語モデル(`crawl-300d-2M-subword.bin`)、個人で作成した英語モデルをロードして使用した際に、`model.get_words()`でUnicodeDecodeErrorが発生した」というIssueが出ており、そこに発生原因と回避方法の情報があります。内容は大体以下のような感じです( **私の理解が間違っているかもなのでリンク先確認推奨です**)。

> この問題は、無効なUTF-8文字列が混入しているトレーニングデータで学習したモデルの使用時に発生する。`get_words(on_unicode_error='ignore')`で無効なUTF-8文字列を無視することで、エラー回避して辞書の全単語を取得できる。

>「辞書に含まれている無効なUTF-8文字列単語を修復して表示」・「普通の文字列を無効なUTF-8文字列に変換して予測に使用」ということが可能だが、無効なUTF-8文字列はfastTextに「英語文字列の単語」として評価されており、予測結果に影響を与えている可能性があるため、解決策ではない。

**Python Implementation return 'utf-8' codec can't decode error #715**

https://github.com/facebookresearch/fastText/issues/715 

**Cannot access to vocabulary in fasttext Python Module ＃1065**

https://github.com/facebookresearch/fastText/issues/1065


# エラーの回避方法(無効なUTF-8文字列を無視)
上記のIssueに出ている`get_words(on_unicode_error='ignore')`の詳細は、fastTextの公式サイトのドキュメントではなく、ライブラリのソースコードに書いてあります。※VSCodeの場合、モデルの変数の型の`_FastText`にCtrl+左クリックで、該当するコードにジャンプ可能

Python module · fastText
https://fasttext.cc/docs/en/python-module.html#model-object
fastText Documentation
https://fasttext.cc/docs/en/html/index.html

**上記2つには記載無し、GitHubのソースに書いてある→「`facebookresearch/fastText`」の 「`python/fasttext_module/fasttext/FastText.py`」の「`get_words(self, include_freq=False, on_unicode_error='strict')`」**
https://github.com/facebookresearch/fastText/blob/main/python/fasttext_module/fasttext/FastText.py#L259

&nbsp;
とりあえずは、以下のように「`get_words(on_unicode_error='ignore')`で無効なUTF-8文字列を無視して辞書の全単語を取得」とやるだけに留めるのが良さそうです。


```py:sample2.py
import fasttext
from fasttext.FastText import _FastText

if __name__ == "__main__":

    # Meta公式サイトからダウンロードしたモデルをロード
    # https://fasttext.cc/docs/en/crawl-vectors.html
    fasttext_model: _FastText = fasttext.load_model(
        "./fasttext-157lang/cc.ja.300.bin"
    )

    # 辞書の全単語をリストで取得
    model_vocab: list = fasttext_model.get_words(on_unicode_error="ignore")

    # リストのサイズ
    print("len: " + str(len(model_vocab)))

    # リストの先頭から10個だけ単語をプリント
    for i in range(10):
        print(model_vocab[i])
```

```txt:実行結果
len: 2000000
の
、
。
に
は
が
を
て
た
で
```


# 関連する情報
## Metaが配布している他の日本語事前学習済みモデル
Meta公式サイトで配布されている、他の日本語事前学習済みモデル(`wiki.ja/wiki.ja.bin`)では、エラーなく辞書の全単語を取得できました。このモデルのトレーニングデータには無効なUTF-8文字列が含まれていないのかもしれません。

https://fasttext.cc/docs/en/pretrained-vectors.html

## fastTextのリポジトリのアーカイブ化
MetaのfastTextのリポジトリは、2024年3月19日にアーカイブ化されています。特にMetaから告知は出ていないようですが、今後のfastTextの更新は無さそうな感じです。**公式配布の事前学習済みモデルの不具合修正や新規配布も無いものと見ていいかもしれません。**
 
https://github.com/facebookresearch/fastText

## gensimでも同様のエラーが発生
gensimでのfastTextモデルの使用に関しても、今回のやつと関連するUnicodeDecodeErrorのIssueが出ていました。エラーの回避方法として、本記事で使用しているMetaのfastTextのPythonライブラリの使用が提案されています。

https://github.com/piskvorky/gensim/issues/2378


# 参考にした記事

この記事を偶然読んで、fastText公式サイトのドキュメントに記載されていない関数(`get_nearest_neighbors`や`get_analogies`等)の存在に気づきました…。とても感謝です。

https://babaye.hatenablog.com/entry/2020/06/27/112657