🔠

LLM 向け日本語データセット(コーパス)の整備メモ

2023/07/07に公開

背景

LLM 向けに日本語データセット(日本語コーパス)を用意したい.

最近の主流(?)は web からテキスト取得(主には cc100ja など, Commoncrawl(web をクロールしてアーカイブしているもの)を利用しているもの)であるが, ただそのままだと無駄なテキストがあるので(e.g. "月を選択 2022年11月 2022年10月 2022年9月 2022年8月 2022年7月 2022年6月 2022年5月 2022年4月 ... " とか), あと文章が途中で切れたりほかの文章と混在していたり(div タグレイアウトが原因であろうか)などで, クリーニングが必須となっている.

クリーニングして一定の品質を保っていれば, あとは end-to-end にテキストデータを LLM に与えて学習させればいい感じになる... はず.

手っ取り早くやる

とりあえず OSCAR 23.01 がそこそこ整形されていて, メタデータもある(ハッシュ値など), ここから始めるとよいでしょう.

https://oscar-project.github.io/documentation/versions/oscar-2301/

そして HojiChar 使ってクリーニング.

https://zenn.dev/if001/articles/cc262413e69e3d

クリーニングスクリプト(仮プロジェクト名 CharShu)

本記事および RefinedWeb を参考にして, 日本語のクリーニングを行うスクリプト一式を以下に上げています(仮プロジェクト名 CharShu)

https://github.com/lighttransport/japanese-llama-experiment/blob/main/README-ja.md

情報

主な元ソース

基本は Commoncrawl と Wikipedia です.

cc100 ja(Commoncrawl 由来)

cc100 ja ではある程度クリーニングされているようですが(読点が . ではなく 。 で統一されている), 文の途中が "..." で切れていたりするので, さらなるクリーニングが必要です.
blog のメニュータイトルなどもそのままだったりするので, 無駄は多い.

458387942   529996569 74360361986 ja.txt

文字数(utf8)

25795332431

25 G 文字(or 25 B 文字)ほど. 元ファイルが 74 GB ほどなので, 概ね 1/3(UTF8 では多くの日本語文字は 3 バイト表現となる)と想定通りでしょうか.

mc4(Commoncrawl 由来)

クリーニング度は cc100 ja 相当か. cc100 と同じく無駄なテキストが多い.

OSCAR(Commoncrawl 由来)

23.01 を使うのがよい. 重複除去は直接はされていないようだが, それぞれにハッシュ値が計算されている.
英語では adult 係数が算出されている. 日本語では算出されていない(日本語のアダルトコンテンツで KenLM で学習して対応が必要)

テキストには meta.quality_warnings で品質の分類がされている. なにも無いのはそこそこ品質が高いものと思われる. しかしいくつか見てみると,

ジャニーズ事務所は11月19日、公式サイトに「正規販売以外でのチケット購入はおやめください」と題する文書を掲載し、
ミクシィの子会社が運営するチケット転売サイト「チケットキャンプ」に抗議している。 この“警告文”とも言える文書で 
は、「11月16日、『チケットキャンプ』という …  
たった3ヶ月で、どんな私も好きになる! 女性のための心理学 主宰 心理カウンセラーの疋田ゆかりです。 こんばんは
。^^ 前回の「アファメーション大作戦」に 早速ご返信を頂きましたー♪ 「本当、呟いたら …
超えの生放送を行い、総勢110組以上が出演予定であることが21日までに分かった。 発表された第1弾出演アーティ 
ストは嵐、いきものがかり、akb48、exile … 

と, 正規化はされていない模様?(もしくは NFKC ではない).
また "..." で文が切れているのもあるので, いずれにせよ文章を ginza(spacy) なりにかけ, 文章(sentence) の抽出と, 途切れた文の切り捨てが必要であろう.

Wikipedia

すでにある程度品質が保たれていると想定できる.

wiki40b でクリーニングされたものが手に入る.
https://zenn.dev/syoyo/articles/a83d44f4d2da1e

主な要素

  • 正規化(normalization)
  • dedup(重複除去)
    • 基本は minhash でハッシュを計算して fuzzy に判定
      • あまり規模が大きくなく(100 GB 以下くらい?), 計算資源に余裕があれば Jaccard 係数算出(naiive には O(N^2) の処理)で判定もあり
    • Suffix array で exact dedup 判定
  • 文章の品質スコアリングし, 低品質文章を除去
  • 文章内での repeat 除去
    • T.B.W.
  • line-wise correction
    • 「今日はいい天気ですね いいね 3」みたいな段落違いがミックスしたのを補正したり?
    • RefinedWeb 参照
    • あとは段落違いのテキストが混在など
    • 日本語だとルビふりのテキストがミックスされるのもあるだろうから, 判定や補正は難しいかも.
      • PPL(perplexity)で判定でいけるか?
      • 別途なにか日本語に特化した文章の自然さ判定も必要になるかもしれません.
  • NSFW(アダルト)要素の除去
    • URL ベースや, KenLM での文章判定ベース
    • 日本語だと分かち書きして, 単語単位で比較でもよいかもしれません.
  • 個人情報関連
    • メアドや電話番号など. 正規表現である程度は対応できる.
    • 氏名と住所が文章内に近しく存在する場合 => 形態素解析など必要か?

line-wise filtering

web からの文章だと, 「今日の天気は... 続きをよむ」などの文章があったりするので, 行単位でこれを除去もしくは修正.

RefiedWeb G.2 参照.

RefinedWeb では, (英語であるが), ルールは以下となっている.

  • If it is mainly composed of uppercase characters (discard);
  • If it is only composed of numerical characters (discard);
  • If it is a counter (e.g. 3 likes) (discard);
  • If it only contains one word (discard);
  • If it is short (≤ 10 words) and matches a pattern (edit):
    • At the beginning of the line (e.g. sign-in);
      – At the end of the line (e.g. Read more...);
      – Anywhere in the line (e.g. items in cart).

if the words in the flagged lines represent more than 5% of the total document words, the document is discarded.

日本語の場合は日本語用のルール定義が必要となる.

正規化, 表記ゆらぎの修正

Python ですと標準ライブラリの unicodedata の normalize でよさそうです.

neologdn もあります(すべてのケースに対応してはいないが, unicodedata.normalize よりは高速に処理してくれるのが期待されるので, 多量のテキストを正規化したいときにいいかも)
https://github.com/ikegami-yukino/neologdn

文章(document)の文(sentence)への分解

https://github.com/megagonlabs/bunkai

bunkai で日本語文章の文分解を行うメモ
https://zenn.dev/syoyo/articles/99c7528863ed5f

https://github.com/wwwcojp/ja_sentence_segmenter

ginza(spaCy) でもできそう

https://ailog.site/2021/10/16/2021/1016/

ただし spaCy(ja_ginza_electra) は精度が高いが処理が遅いので注意.

文章の結合

cc100 ja データセットでは一文が改行で分かれているだけです.

複数行の文章(文節)が関連しているかどうか調べ, 関連していたら一つにまとめたい.

TODO.

繰り返し文の除去

文章内で繰り返し文があるかどうか判定.
python でぺろっと使えるライブラリはない模様?

LLM データセット向け 日本語文章の繰り返しを判定するメモ
https://zenn.dev/syoyo/articles/ff5f4e41f3124c

で自作するとよいでしょう.

文章の長さ

RefinedWeb の C. Dataset analysis に文章の長さ(tokens)の解析がある.
概ね平均は 200 ~ 250 tokens というところかしらん.

これを参考に, 短すぎたり, 長すぎたりする文章は弾く.

HojiChar ではデフォルト 200 字(UTF-8 chars) ~ 50,000 字とある.

https://github.com/HojiChar/HojiChar/blob/8b749dfef50752dc0c6bb18220198cbc2da2e7f8/hojichar/filters/document_filters.py#L213

Scaling Language Models: Methods, Analysis & Insights from Training Gopher
https://arxiv.org/abs/2112.11446

では英語であるが

  • 50 ~ 100,000 words 以外は除去

単語ベースの fintering

Scaling Language Models: Methods, Analysis & Insights from Training Gopher
https://arxiv.org/abs/2112.11446

ではさらに, 以下のフィルタリングを行っている

  • 平均 word 字数が 3 ~ 10 以外は除去
  • symbol-to-word ratio greater than 0.1
    for either the hash symbol or the ellipsis
  • more than 90% of lines
    starting with a bullet point, or more than 30% ending with an ellipsis
  • We also require that 80%
    of words in a document contain at least one alphabetic character
  • apply a "stop word" filter, to
    remove documents that do not contain at least two of the following English words: the, be, to, of, and,
    that, have, with;

日本語に適用するとなると

でしょうか.

文章の品質スコアづけ

日本語の文章のクオリティを [0, 100] みたいな感じでスコア算出したい.

基本は KenLM で Perplexity(PPL) を算出して, スコア低いのが品質高いと判定する.

ただし日本語では PPL が低ければ品質が高いというわけでもないという報告もあり,

https://www.anlp.jp/proceedings/annual_meeting/2021/pdf_dir/C2-3.pdf

日本語に適した文章の品質スコアリングが求められるかも
(まあ LLM の場合は, 学習の段階では英語などと同様に PPL 低いのを使い, ファインチューンの段階でそれぞれの用途に適したハイクオリティな日本語データセットを使うので対応してもよいかもしれない)

dedup

Fuzzy dedup(minhash)

LLM 日本語データセット向けに C++ で minhash 重複除去を行うメモ
https://zenn.dev/syoyo/articles/698fc33209ff74

Exact dedup(suffix array)

LLM コーパス構築用: deduplicate-text-datasets で Exact Dedup するメモ
https://zenn.dev/syoyo/articles/1d14aa3245dcfa

LLM 日本語データセット(コーパス)構築向け: C++ Exact dedup at scale(Suffix Array 構築編)
https://zenn.dev/syoyo/articles/9b397158084dde

RefinedWeb では Exact dedup で match したものは削除(ExactDedup-Cut)している.
これにより文章が分断されてしまいおかしな文章になることがあるが, LLM の性能にはそれほど影響はないっぽいようである.

文法の誤り修正

https://github.com/youichiro/transformer-copy

このあたりから調べればなにかわかるかもしれません.
データセットのトークン数がほしいときに, Perplexity での品質スコアリングで足切りした文章をうまく直してデータセットをうまく増やしたいときとか.

Universal Dependencies

各言語の構文アノテーションのデータセット

https://udjapanese.github.io/docs/

https://www.jstage.jst.go.jp/article/jnlp/26/1/26_3/_pdf

UD ベースでなにか行けるかも

LLM 向けの整形

数字

dedup で重複判定するとき, 数字は 0(or なにかしらの記号) に置き換えるのがよくある(はず).

2023 年 7 月 => 0 年 0 月

など.

(0 にして dedup 判定は cc_net の論文参照)
RefinedWeb とかのコーパスではクリーニング後のテキストで数値は残っている.

https://qiita.com/Hironsan/items/2466fe0f344115aff177#前処理の種類と実装

https://zenn.dev/deepblackinc/books/53ff1d10304ef7/viewer/06feb1

一方, これらの記事では, 入力の時点で, 日付や数量, 金額(りんご 100 g, バナナ 150 円とか)などはゼロ(or placeholder)にする, となっています.

BERT 時代(encoder で認識系(?))は元データの時点で 0 は有効でしたが, LLM(GPT など decoder で 生成系)時代では, ゼロ化はせず, 生成のため具体的な数字がテキストにある必要があるかんじですかね.

また, より具体的な数字の扱い(富士山の高さは N m)というのは, fine-tuning のときに行うのがいいかもしれません.

ただ, Chinese LLaMa のように, 既存 LLaMa(英語) に対して incremental に学習する場合は, すでに英語の時点で基礎的な知識が習得されていると期待できるので, 数字が具体的にあると(追加)学習へのノイズとなってしまうような気もちょっとはします...
=> RedPajama(LLaMa) や RefinedWeb(Falcon) を見ても, 数字は置き換わっていないので, 日本語で数字があるものだとノイズが乗って性能が落ちてしまうようなきもする.

数字のあつかい, 要検証ですね.

あと, 数字を置き換える場合, できれば日にちなどきちんと検出して, それらだけを置き換えるようにできるといいでしょう.
(https://qiita.com/tkscode/items/394f0d53abeed034e659 の NormalizeNumexp が使えそう)

個人情報

電話番号やメアドのマスキング

https://github.com/HojiChar/HojiChar/blob/bca0c4980fb2398086509f61be71a45965de0ec5/hojichar/filters/document_filters.py#L624

人物名 + 住所みたいなのは形態素解析して判定できるかしらん?

日本語特化のクリーニング

スペースが文中に多いものは, blog ナビメニューなどの可能性が高いので除く.

情報学 遺伝育種科学 作物生産科学 園芸科学 植物保護科学 昆虫科学 生物資源保全学 ランドスケープ科学 農業社会構造 地域環境工学、農村計画
学 ...

ある程度単語長があるも, 一文中に句点がなかったり助詞などが無いのものぞく
(閾値は 20 単語くらいがよいか?)

全ての所在中央図開架中央図1F新着中央図2F参考中央図1Fシラバス中央図1F学生選定中央図1F文庫・新書中央図2F教科書中央図2F留学
生中央図1Fカウンター中央図1F視聴覚中央図2F郷土中央図1F多文化中央図1F英語多読中央図1F児童中央図2F大型地図中央図書庫3F西中央図2F大型美術中央図2F災害中央図2F

... で終わっている文は取り除く(もしくはセンテンスに分け, ... で終わっていない有効なセンテンスだけのこす)

【 つれづれ。。。 】 「トライやる・ウィーク」によって、なんだか新鮮な気持ちで お仕事ができるようになったソウルライフレコード店長の小杉です。 おそらくご存知無い方も多いかもしれませんね、 「トライやる・ウィーク」。 ...

なにか関連性のあるもの

https://jedworkshop.github.io/jed2022/materials/jed2022_d-2_谷中.pdf

高速な文法誤り訂正機能を持つ
日本語ライティング支援システムの構築
https://www.jstage.jst.go.jp/article/tjsai/37/1/37_37-1_B-L22/_pdf

未分類

霧島酒造は、宮崎県都城市に工場を置く日本の酒造業者で、キャッチコピーは「くつろぎの霧島」。社名や銘柄に使われている「霧島」の由来は、宮崎県と鹿児島県の県境にそびえる「霧島山」から名付けられたとのことです。創業者である江夏吉助が都城で芋焼酎の製造を始めたのが会社の起源であり、工場近くで掘り当てた天然水を「霧島裂罅水」と命名し、それ以降は一貫してその水で仕込んだ焼酎を中心に作り続けていいます。22日の日本株市場は、28000円での底固めの動きが継続しそうだ。21日の米国市場ではNYダウが45ドル安だった。新型コロナ感染急拡大で中国各地で都市封鎖が
再開されたため、世界経済への影響を懸念した流れから売り優勢の展開。米連邦準備制度理事会(FRB)がタカ派姿勢を弱めておらず、積極的な利上
げを継続する断固とした姿勢を背景とした金利先高観からハイテク株へは利益確定の動きが強まった。その後、サンフランシスコ連銀のデイリー総裁が行き過ぎた利上げに慎重な姿勢を見せたため、下げ幅を縮小して取引を終えている。シカゴ日経225先物清算値は大阪比75円高の28045円。円相場は1ドル142円00銭台で推移している。

のような, 一文中に関係のない文章が混在しているのはどうしたらよいか.
=> 照応解析や構文解析で関連性を判断する方法がありそう?

緊急価格変更★12月7日よりクーポンで111円★国産すっぽん黒酢《約1ヵ月分》■ネコポス送料無料■代引き・日時指定不可すっぽん/スッポン/黒酢/アミノ酸/ダイエット/国産【TB1】【deal1105】【dealreiwa12】

みたいなタイトルのようなもの.
スペースはないが, ひらがないくつか含んでいる.
助詞や動詞の含有率で判断がよいか?
(あとは /, みたいなセパレータの個数など(word-to-symbol ratio))

LLM で文章つくるのは?

生成AIに“生成AIが作った文章”を学習させ続けるとどうなる? 「役立たずになる」と英国チームが報告
https://www.itmedia.co.jp/news/articles/2306/21/news059.html

綺麗すぎたり多様性が無いとダメになるようだ.

一方で, (人間が介在する必要はあるが) LLM で多様性を増やしていい感じにするのも提案されている

Increasing Diversity While Maintaining Accuracy: Text Data Generation with Large Language Models and Human Interventions
https://arxiv.org/abs/2306.04140

日本語の場合はどうなるかは要検証だが, rinna などで多量に LLM 用データセットを生成するのもアリだと思われる.

Token 量

Chinchilla scaling law によれば, LLM 1B あたり 20B tokens が最適とある.
たとえば 7B なら 140B tokens.

とはいえ日本語の性能のよい LLM 目指すにしても, 英語など多言語のデータセットとトークン量のほうが重要らしい(これを指摘している論文は忘れてしまいました...)ので, 英語などの Tokens 量に対して日本語は 5~10% 程度(全量が 1T tokens であれば, 日本語は 50B ~ 100B tokens)で十分であると思われます.

時間情報

NLP Hacks Vol.3で「時間情報表現抽出とルールベース解析器のこれから」という題で登壇しました
https://zenn.dev/yag_ays/articles/e5fc8a03927376

TODO

  • 文章の結合をうまくやる方法を探す

Discussion