記事概要と検証環境と検証対象モデル
「Python 3.11
」とPythonライブラリの「fastText 0.9.2
」で、Meta(旧Facebook)公式が配布しているfastTextの日本語事前学習モデル(fasttext-157lang/cc.ja.300.bin
)をロードし、辞書の全単語をmodel.get_words()
で取得しようとすると、文字コードに関するエラーが出てしまう現象があるので、エラー回避方法や発生原因をまとめました。間違っている部分があったら指摘大歓迎です。
検証環境
-
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コーデックで文字のデコードに失敗)が発生します。
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 # 上と同じ
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
Cannot access to vocabulary in fasttext Python Module #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
とりあえずは、以下のように「get_words(on_unicode_error='ignore')
で無効なUTF-8文字列を無視して辞書の全単語を取得」とやるだけに留めるのが良さそうです。
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])
len: 2000000
の
、
。
に
は
が
を
て
た
で
関連する情報
Metaが配布している他の日本語事前学習済みモデル
Meta公式サイトで配布されている、他の日本語事前学習済みモデル(wiki.ja/wiki.ja.bin
)では、エラーなく辞書の全単語を取得できました。このモデルのトレーニングデータには無効なUTF-8文字列が含まれていないのかもしれません。
fastTextのリポジトリのアーカイブ化
MetaのfastTextのリポジトリは、2024年3月19日にアーカイブ化されています。特にMetaから告知は出ていないようですが、今後のfastTextの更新は無さそうな感じです。公式配布の事前学習済みモデルの不具合修正や新規配布も無いものと見ていいかもしれません。
gensimでも同様のエラーが発生
gensimでのfastTextモデルの使用に関しても、今回のやつと関連するUnicodeDecodeErrorのIssueが出ていました。エラーの回避方法として、本記事で使用しているMetaのfastTextのPythonライブラリの使用が提案されています。
参考にした記事
この記事を偶然読んで、fastText公式サイトのドキュメントに記載されていない関数(get_nearest_neighbors
やget_analogies
等)の存在に気づきました…。とても感謝です。