🥷

SpacyTextSplitterでユーザ辞書を使う

2024/03/08に公開

文意が保たれるチャンクを生成したい!

LLMを使ってRAGアプリケーションを作成する場合、皆さんはどのようにチャンクを生成していますか?様々な方法がありますが、Quick Startなどで文字数などでチャンキングしてるから、そのまま文字数によるチャンキングを採用しているかもしれません。しかし、これだと分割されてほしくない箇所で分割されてしまっていることはないでしょうか?

例えば、

政治的な虚偽報道や悪意のあるでっち上げを作成するためにも使用される。選挙運動で対立候補を陥れるネガティブ・キャンペーン、政権政党への批判、戦時下における扇動などの工作にも使われている。2023年、AI技術を駆使しニュース番組の画面に見せかけた上で当時の日本の内閣総理大臣岸田文雄が卑猥な言葉を発してるように見せたディープフェイク動画がSNSで拡散された。

上記のような文章があったとします。これを50文字毎、10文字の重複を許す形で分割した場合、以下のような結果になります。

Chunk 0 (length: 50): 政治的な虚偽報道や悪意のあるでっち上げを作成するためにも使用される。選挙運動で対立候補を陥れるネガテ
Chunk 1 (length: 50): 立候補を陥れるネガティブ・キャンペーン、政権政党への批判、戦時下における扇動などの工作にも使われてい
Chunk 2 (length: 50): の工作にも使われている。2023年、AI技術を駆使しニュース番組の画面に見せかけた上で当時の日本の内
Chunk 3 (length: 50): た上で当時の日本の内閣総理大臣岸田文雄が卑猥な言葉を発してるように見せたディープフェイク動画がSNS
Chunk 4 (length: 17): フェイク動画がSNSで拡散された。

この結果はいかがでしょうか?文の途中で区切れていたり、文意が通るか通らないか判断が難しいところで区切れている印象をもたれるかと思います。RAGの精度を鑑みたとき、ある程度意味が変わらない粒度で文章を分割したいところですが、上記はそれを満たしているようには見えません。

LLMが登場する以前では、日本語の自然言語処理では前処理の一環として形態素解析を行うことが一般的でした。このチャンキングする場合でも、形態素解析器を活用することで文意が通るところで分割されることが期待できます。
一方で、形態素解析器を用いることでしばしば遭遇する問題があります。それは 専門用語が分割されてしまう ということです。

この記事では、SpacyTextSplitterでユーザ辞書を反映するステップについてまとめていきます。

この記事のコードはこちらを参照してください。

https://github.com/toohsk/JpnSpacyTextSplliterExample

日本語文を形態素解析していく。spaCyで

では、実際に形態素解析を行っていきましょう。SpacyTextSplitterは、LangChainで提供されているTextSplitterの一つで、spaCyを利用しています。spaCyは世界の75言語以上をサポートしている自然言語処理のライブラリです。提供されているモデルをspaCyにロードすることで各言語特有の処理をサポートできるようになります。日本ではGiNZAというモデルを利用することで形態素解析できるようになります。上記のリポジトリのコードを実行することで形態素解析された結果を参照できます。

元の文章は以下のようなものを想定しています。

『アナと雪の女王』(アナとゆきのじょおう、原題:Frozen)は、ウォルト・ディズニー・アニメーション・スタジオ製作の映画です。

形態素解析した結果がこちらです。

python pos_tagging.py

0 『 補助記号-括弧開
1 アナ 名詞-普通名詞-一般
2 と 助詞-格助詞
3 雪 名詞-普通名詞-一般
4 の 助詞-格助詞
5 女王 名詞-普通名詞-一般
6 』 補助記号-括弧閉
7 ( 補助記号-括弧開
8 アナ 名詞-普通名詞-一般
9 と 助詞-格助詞
10 ゆき 名詞-固有名詞-一般
11 の 助詞-格助詞
12 じょ 助詞-終助詞
13 おう 感動詞-一般
14 、 補助記号-読点
15 原題 名詞-普通名詞-一般
16 : 補助記号-一般
17 frozen 名詞-普通名詞-一般
18 ) 補助記号-括弧閉
19 は 助詞-係助詞
20 、 補助記号-読点
21 ウォルト 名詞-固有名詞-人名-一般
22 ・ 補助記号-一般
23 ディズニー 名詞-固有名詞-人名-一般
24 ・ 補助記号-一般
25 アニメーション 名詞-普通名詞-一般
26 ・ 補助記号-一般
27 スタジオ 名詞-普通名詞-一般
28 製作 名詞-普通名詞-サ変可能
29 の 助詞-格助詞
30 映画 名詞-普通名詞-一般
31 です 助動詞
32 。 補助記号-句点

品詞の粒度に分割されているかと思います。
ここで着目されたいのは、冒頭の アナと雪の女王 という部分です。有名な邦題ですが、残念ながら固有名詞として扱われず、各品詞に分解されています。これは日本語における自然言語処理の難しいところで、どの固有名詞を固有名詞として扱うかは目的によって異なります。

sudachipyでユーザ辞書を使う

このような固有名詞として扱ってほしい単語はユーザ辞書として登録する必要があります。
GiNZAは内部でsudachipyを利用しています。したがって、sudachipyで扱える形式でユーザ辞書を作成することで単語を追加することができるようになります。
sudachipyでは、ユーザ辞書を作成するためのコマンドが用意されており、ユーザはCSV形式で追加する単語を定義するだけでユーザ辞書を登録することができます。
任意にディレクトリを作成し、そこにCSVファイルを作成します。リポジトリ内では.sudachi_dictという名前のディレクトリを用意し、user_terms.csvというファイルを用意しました。以下のコマンドを実行することで.sudachi_dict以下にユーザ辞書を作成することができます。

sudachipy ubuild \
  -s .env/lib/python3.10/site-packages/sudachidict_core/resources/system.dic \
  .sudachi_dict/user_terms.csv \
  -o .sudachi_dict/user.dict

# ユーザ辞書が作成されているかを確認。user.dictファイルがあればok
ls .sudachipy

ユーザ辞書が作成済みの場合、上書きすることができないので、ファイルを削除してから作成してください。
次に、作成した辞書のパスをコンフィグファイルに追加する必要があります。

このコンフィグファイルはinstallしたsudachipy内にあります。今回、リポジトリのコードでは仮想環境をpyenvで構築することを想定しており、以下の説明はその前提で進めていきます。仮にpoetryなどのパッケージマネージャなどで仮想環境を作成した場合、ご自身で置換して試してください。

.envという仮想環境を構築したとして、sudachipyは.env/lib/python3.XX/site-packages/sudachipyにあります。この中のresources/sudachi.jsonがコンフィグファイルになります。エディタで開くとデフォルトの設定がいくつか記述されているので、以下の例のようにuserDictキーとユーザ辞書へのパスを追加してください。

{
    "systemDict" : null,
    "characterDefinitionFile" : "char.def",
    "userDict" : [".sudachi_dict/user.dic"],
    ...
}

編集できたらあらためて、先ほど実行した形態素解析のスクリプトを実行しましょう。するとアナと雪の女王のところが一つの固有名詞になって出力されていることが確認できると思います。

python pos_tagging.py

0 『 補助記号-括弧開
1 アナと雪の女王 名詞-固有名詞-一般
2 』 補助記号-括弧閉
3 ( 補助記号-括弧開
4 アナ 名詞-普通名詞-一般
5 と 助詞-格助詞
....

SpacyTextSplitterでユーザ辞書を反映していく

ここで本来の目的の文意が通るチャンキングは可能なのか?を検証していきます。
ユーザ辞書を定義せずにSpacyTextSplitterで文字数を100文字重複を10文字として、チャンクを生成してみます。

Chunk 0 (length: 34): 政治的な虚偽報道や悪意のあるでっち上げを作成するためにも使用される。
Chunk 0 (length: 58): 選挙運動で対立候補を陥れるネガティブ・キャンペーン、政権政党への批判、戦時下における扇動などの工作にも使われている。
Chunk 1 (length: 72): 2023年、AI技術を駆使しニュース番組の画面に見せかけた上で当時の日本の内閣総理大臣岸田文雄が卑猥な言葉を発してるように見せたディープフェイク
Chunk 1 (length: 13): 動画がSNSで拡散された。

結果としては、多くが句点で区切られています。ただし、最後のチャンクが惜しくも区切れてほしくないところで区切られてしまっています。

なので、フェイク動画という単語をユーザ辞書に追加して、再度実験してみましょう。

まずは辞書の更新です。以下の一行をユーザ辞書に追加します。

フェイク動画,4786,4786,5000,フェイク動画,名詞,固有名詞,一般,*,*,*,フェイクドウガ,フェイク動画,*,*,*,*,*

その後、先ほど生成したユーザ辞書がある場合はそれを削除してからユーザ辞書を生成します。

rm -rf .sudachi_dict/user.dict

sudachipy ubuild \
  -s .env/lib/python3.10/site-packages/sudachidict_core/resources/system.dic \
  .sudachi_dict/user_terms.csv \
  -o .sudachi_dict/user.dict

コンフィグファイルにユーザ辞書のパスが追加されているかを確認し、実行します。

python text_split_spacy.py

Chunk 0 (length: 34): 政治的な虚偽報道や悪意のあるでっち上げを作成するためにも使用される。
Chunk 0 (length: 58): 選挙運動で対立候補を陥れるネガティブ・キャンペーン、政権政党への批判、戦時下における扇動などの工作にも使われている。
Chunk 1 (length: 85): 2023年、AI技術を駆使しニュース番組の画面に見せかけた上で当時の日本の内閣総理大臣岸田文雄が卑猥な言葉を発してるように見せたディープフェイク動画がSNSで拡散された。

今回は期待通り、フェイク動画が区切られる事なくチャンクが生成されました。

まとめ

SpacyTextSplitterでユーザ辞書を反映する方法を、sudachipyでユーザ辞書を作るところから説明してきました。そしてユーザ辞書を使うことで文意が損なわれないところでチャンクを生成することができるようになりました。
この記事が、何かしらの形でLLMとRAGアプリケーションの精度向上に寄与しましたら幸いです。

Discussion