ウェブの日本語テキストをクリーニングするための基本的な処理コードと課題


はじめに

2024年は皆で大規模言語モデルを作るので、日本語のテキストを皆でクリーニングしています。

クリーニングのための、軽い試行錯誤を行いました。
本記事では、清掃作業がどこまで進んだのか、今後やるべきこと、などについてまとめています。

関連記事

コード

本記事のコードは、google colabで実行できます。

githubのrepoはこちらです(CommonCrawlのダウンロードプロジェクトと一緒のrepoですが、今後、分離する予定です)。gitのrepoはこちらです(CommonCrawlのダウンロードプロジェクトと一緒のrepoですが、今後、分離する予定です)。

また、コード自体は、shoyoさんのrepoを大いに参考に(流用)させていただきました。


背景 (本筋ではありません)

著作権周りの話です。間違っていたら、すみません(教えてください)。

Webデータは誰が集めて公開しているのか? →CommonCrawl

世界中のWeb上のテキストは、CommonCrawlという非営利事業で収集、公開されています。Webテキストは著作物なので、本来は第三者が勝手に公開してはいけないのですが、CommonCrawlの本拠地であるアメリカでは「フェアユース」という概念が明文化されており、本件のような公益性のある事業は、合法であるとの判例が出ているようです※。

※日本での扱いについて:
本国ではフェアユースの概念が明文化されていないため、同じことをするのは難しいと思います。そのため、CommonCrawlのデータをアメリカのサーバーからダウンロードして、組織内部で利用するという形態を取ります。2024年時点で、諸々の議論が国内で進行中ですが、Web上の公開データをモデルの事前学習に使う行為そのものは、著作権法上、OKであるとの解釈で、言語モデルの開発・公開がなされている模様です。

テキストデータベースはどこにあるのか?

CommonCrawlではhtmlデータをそのまま収集し、公開しています。
ただ、言語モデルの学習には、そのままでは使いにくいので、テキスト部分だけを抜き出したデータセットが、多数公開されています。mC4データセットなどが有名です。

なぜ、クリーニングが必要なのか?

mC4データセットなどには、大規模言語モデルの事前学習に用いるテキストとして、多量のノイズ情報が含まれます。
以下のようなものが代表的です。

  • html, javascriptタグ類

  • リンク (「Topへ移動」など)

  • 自動生成された文字列 (販促サイトでよくある、キーワードの羅列: 「ダイエット 飲むだけ 10kg げっそり」など)

  • 多量のコピペ文章

  • 公序良俗に反する文章

  • 文法的に誤った/未完成の文章

など。

加えて、筆者の体感では、CommonCrawlで解析するWebサイトの半数程度が、「販促系」、「R18系」のページとなっています。そのようなページを作成するための言語モデルを作りたい場合は、問題ないのですが、他の用途に使いたい場合は、学習データとしてのバランスが悪すぎる印象です。

そのため、ルールベースや機械学習の手法を用いながら、不適切なテキストやページを処理する作業が、大規模言語モデルの事前学習においては重要です。

処理の概要

クリーニングで行う代表的な処理は以下のとおりです。

  • 文字列の正規化 (変な文字コードを消す)

  • ルールベースでの、不要な文字列の削除

  • 機械学習ベースでの、不要な文字列の削除

  • 重複の削除

本記事では、google colabの実行結果を参照しながら、「重複の削除」以外の処理について説明します。

自動実行の結果

文字列を自動クリーニングするためのクラスを軽く作りました。それを実行した結果は以下のとおりです。

1,2つ目の記事: 生八ツ橋/廃棄物をチップ
不要なスペースなどが削除されています。
(本当は、「生八ツ橋のタグまとめ」のようなヘッダー部分も、もう少しキレイに掃除したいです)

3つ目の記事: 愛媛、時々フランス
文章のはじめの「愛媛、時々フランス chez …」という文字列が、日本語として成立しないと判断されたため、削除されています。

4つ目の記事: [V系]
諸々のクリーニングの後、記事そのものが「NG」と判断されたため、最終出力が空白("")となりました。

以下、内部処理を見ていきます。

正規化

怪しげな文字コード消したりします。

どこまで正規化するかは、プロジェクトの趣旨や好みによります。
(全角記号を半角にする、「。」と「.」の使い分け、数値をマスキングする、などなど)

今回は、適当に文字コードを修正する程度の正規化になっています(コード)。

参考

ルールベースの処理

パラグラフ&文章への分割

テキストは、「。」などで区切られた文章ごとに処理したいので、元の文字列をパラグラフー文章の二重リストに変換します(コード)。
このあたりはルールベースで行っており、精度は100%ではありません。大いに改善の余地があります。

ルールベースでの文章チェック(その1)

webサイトでは、[続きを読む]のようなリンクが多く登場します。しかしこのようなテキストは不要なので、ルールベースで削除していきます(コード)。

次に、テキストの形態素解析を行い、名詞や記号だらけの文章を削除します。「ジュース オススメ おいしい 最高」のような、自動生成されたテキストを削除するのが目的です(コード)。

クリーニング後の様子は以下の通り。

ルールベースでの文章チェック(その2)

今回のプロジェクトでは、良質な日本語の文章を抽出することが目的です。
そのため、文末が「。」、「!」などで終わらないテキストは未完成のものであると判断して、削除することにしました(コード)。※

※このやり方を単純に適用すると、文章内の「見出し」も消えてしまうリスクが高いです。改善の余地があります。

ルールベースでの文章チェック(その3)

最後に、lineが開発したテキストフィルタ「hojichar」を使って、文章をフィルタリングしていきます。

NGワードの辞書などが標準で実装されており、R18サイトや差別表現などを効率的に除くことができます(完璧ではありません)。
デフォルトの辞書が、やや厳しすぎた(例えば「死」という単語がNG)ので、少し緩めて実装しました(コード)。

また、このライブラリは個人情報を削除する機能があります。
正規表現を活用し、例えば電話番号を「123-4567-8901」から「123-4567-XXXX」のように変更してくれます。emailも対応していました。住所は未対応であるように思いました。

上記の文章には、何らかのNGワードが含まれていたようで、この段階で出力が空白になりました。

機械学習によるテキスト分類

ルールベースのフィルタリングの特長は高速であることですが、判別精度には限界があります。そこで今回は、fasttextという自然言語系のライブラリで「ゴミ」記事を判定することにしました(コード)。
fasttextの特長は、GPUが不要である点と、非常に高速な点です。

データセットの作成

はじめに、mc4データセットからランダムに記事を取り出し、筆者の主観で、「good」、「bad」のラベル付けをしていきます。

例えば以下のサイトは、いかにもよくある販促サイト(しかもコピペっぽい)なので、「bad」のラベル付けをしました。
このようなアノテーションを、700件ほど行いました。もっと件数を増やせば、精度は上がるはずです。

蛇足: ラベル済みデータの保存

ラベル済みデータを保存する際は、「ラベルーテキスト」という内容ではなく、「ラベルーデータID」としました(こちら)。
テキストそのものを保存してしまうと、データセットを公開する際に、著作権の問題が発生するためです。

機械学習

以下の処理で機械学習を行いました。

  1. Mecabによって日本語の形態素解析を行う

    1. 名詞や動詞のみを取り出す or すべての語句を使う などはハイパーパラメータです(今回は後者を利用)

  2. ラベル済みデータをfasttextの形式に変換する(__label__1 イラストレーター 福士…)

  3. train/validation/testに分類する

  4. fasttextで学習する

    1. ハイパーパラメータはほとんどいじっていません。改善の余地がたくさんあります

GoogleColabのリソース制約(RAM)もあり、サンプルコードでは精度が0.58※となりました。
この結果は、改善の余地がたくさんあることを示しています。

※どの指標だったかは、失念しました。maxが1です。colabではwordNgrams=1にしましたが、wordNgrams=2にすると、スコアが0.1ー0.2ほど上がります。

最後に、学習済みのモデルで推論を行うことで、記事を判定していきます。

(実のところ、4つめの記事は、機械学習で判定するまでもなく、
ルールベースのフィルタで「ゴミ」判定されています)

参考: 改善の余地はどこにあるか?

本記事のコードは、突貫で作ったものですので、改善の余地がたくさんあります。「不要な見出し」がテキスト中にたくさん残っていますし、「ゴミ記事」の判別精度もイマイチです。加えて、並列化処理にもまだ対応していません。

端的に言えば、数百GBクラスのテキストを、高精度かつ高速に処理するscriptが必要です。

改善のアイデア例を、以下に示します。

  • "文章の正常さ"の指標とも言える「Perplexity」によって、おかしな日本語を削除するという手法があります。

  • 文章内の重複を判定する「repetition removal」も有効な手法です(コード)。

    • ただ、上記のコードは実行速度が遅く(恐らくbunkaiライブラリが原因)、普通の文章も弾いてしまっていたので、今回は使いませんでした

  • 日本語の文章がどこで区切られるかを判定する処理が重要です(参考)

    • 例えば、「◯◯のすすめ 本日は、◯◯について説明します」というテキストを、"◯◯のすすめ", "本日は、◯◯について説明します"に分割してあげると、テキスト処理がやりやすくなります。

    • syoyoさんによると、transformerベースで動く(?)、wtpsplit というモジュールがおすすめだそうです(24年2月時点)

      • 当該論文でも高性能な結果が報告されているのですが、実際に学習済みモデルを使ってみると、日本語の分解性能は壊滅的でした。

      • アルゴリズムは良さそうなので、モデルのトレーニングからきちんと行う必要があります。ただ、環境構築が面倒そうだったので、一旦やめました。

      • 速度についてもチェックが必要です。

まとめ

本記事では、Web上の雑多なテキストをクリーニングする手法について、軽く解説しました。
最終的には、膨大なテキストをクリーニングするモジュールを実装する必要があるのですが、基本的に、個別のクリーニング処理は、google colabで簡単に実装できるほど、単純かつ軽量です。

記事の「はじめに」で案内した通り、大規模言語モデルを作るプロジェクトが走っておりますので、もし良いアイデアやコードをお持ちの方は、大歓迎です。
誰でも参加できるオープンソースのプロジェクトになっています。参加方法などの詳細は、以下のページを参照ください。


いいなと思ったら応援しよう!