0.1-1B程度の日本語・大規模言語モデルを作る練習日記
はじめに
最近は大規模言語モデルを作っています。
最終的には10B級のモデルを作るのですが、その前に、0.1-1b程度で練習をします。
本記事は、その取り組みのメモ・日記です。(逐次更新します)
注意点
・日記なので、内容はかなり雑多です。
・練習を兼ねたcode実装なので、先端知見が含まれているとも限りません。
・どんなことをやっているか、時系列を追って理解する参考にはなるかもしれません。
3/6頃 コード確認
・「標準コード」を支給頂いたので、それをトレースした。
・諸々の処理(pipe)が繋がっていないので、それをつなげる必要有り
3/7 パイプライン化
・初心者向けに、shコマンドを一発叩くだけで、諸々の処理が終わるパイプラインの構築が必要である。
・事前学習程度までのパイプは繋がった。
https://github.com/hatakeyama-llm-team/llm/tree/dev_hatakeyama/codes
・練習でWikipediaの日英記事、それぞれ100万件を0.1Bモデルに事前学習させた。
・わかってはいたが、0.1bモデルは流石のクオリティの低さであった。
つまづき(?)点
学習の際、train_samplesと,train_tokensを設定する項目があった。
train_tokensを、実際のdataset sizeにしておけば、そのタイミングで学習は終わる。
train_samplesは適当に大きなサイズにしておけば良いのだが、これをあまりに大きくしすぎると、memory errorが発生した。
(以下は、30000B token相当に設定した例)
train_samples=$(( 30000 * 1000 * 1000 * 1000 * 2 / ${seq_len} ))
小さすぎると、train_samples側の基準でtrainが終わってしまうので、1000Bくらいにしておくのが良いか。
3/8 0.3bの学習
0.1bがアホすぎたので、0.3bで回してみた
A100 (80GB) x2で計算。
バッチサイズは、deepspeed 0、global batch size 64で、ちょいど良い感じであった
wikipedia(200件、日英)は3.6b token。
学習速度から推定すると、37000 sec (10時間程度)で1epoch
学習後は、0.1bよりも知性を感じる結果となった。
(1 epoch = 27466 step後)
つまづき(?)点
・本teamでは、特定の順番でデータを学習させることを計画している。
・まずはデフォルトで、データがどの順番に学習されているかどうかの確認が必要であった。
・Megatraon-DeepSpeed内のpretrain_gpt.pyを一時的にhackして、t.txtに実際に学習させる文章を出力する処理を暫定で追加した。
def get_batch_pipe(data):
"""Modification of `get_batch` to work on `next(data_iterator)` instead of `data_iterator`"""
args = get_args()
tokenizer = get_tokenizer()
#実際の学習データを確認するscript
import sentencepiece as spm
model_path = "../../data/tokenizer/tokenizer.model"
sp = spm.SentencePieceProcessor(model_file=model_path)
with open("t.txt", "a", encoding='utf-8') as f:
token = (data['text'])
shape = token.shape
f.write(str(shape) + "\\n")
txt = sp.decode(token[0].tolist())
f.write(txt)
・その結果、学習直前にdataをindexするタイミングで、データのshuffle処理が自動実行されていることがわかった。
・https://github.com/microsoft/Megatron-DeepSpeed/blob/main/megatron/data/gpt_dataset.pyの中で、np_rng.shuffleという処理が3回行われるので、そこをコメントアウトすることで、shuffleを防ぐことができた。
3/8 deep speedのzero stage チェック
deepspeedのzeroを増やすとどういうメリットがあるかを調べることにした
ベース: 0.3bモデル
stage 0
global batch: 64
(2gbほど、別プロセスで使ってたので注意)
stage 1
ちょっとvramの使用量が減った?
速度はほぼ変化なし
・Stage 2以降は、エラーが出ました。追加のconfig設定が必要なようです。
3/9 データの学習順序がモデルに与える影響の確認
・0.3bモデル
・Wikipedia 英語100万件、日本語100万件の順序で学習
・1 epochで24k step
・英語のみを学習させた場合(@ 10k step)
・英語→日本語の順に学習させた場合(@ 24k step)
・日英がshuffleされた場合 (以前の検討モデル。penaltyを一部変更)
つまづき(?)点
・想定とは異なり、完全に英→日の順番で学習させてしまうと、LLMが適切に日本語能力を獲得できないことが判明
・初期の学習時、英語用にモデル重みが固定してしまうことが原因?
・学習順序に、グラデーションをかけていくことが重要かもしれません。
・Perplexityも計算してみました。
def perplexity(model, tokenizer, text) -> torch.Tensor:
tokenized_input = tokenizer.encode(
text, add_special_tokens=False, return_tensors="pt"
).to(model.device)
with torch.inference_mode():
output = model(tokenized_input, labels=tokenized_input)
ppl = torch.exp(output.loss)
return ppl.item()
英→日の場合、、
今日は: 354
富士山は: 422
I have a : 357
Functional polymers: 11
でした。やはり、日本語に対する困惑度が高いようです。
学習初期はlearning rateが高いこともあり(?)、英語だけを学習させると、日本語の能力が身につきにくいようです。
3/11 日英Wikipediaの学習順序を最適化する
0.3bモデル
Wikipedia 英語100万件、日本語100万件を学習
1 epochで24k step
3/9の検討で、完全に英語→日本語の順番では良くないことが判明
今回は、3 Stageに分けてデータセットを配備
1: 日本語9万件、英語9万件
2: 日本語9万件、英語81万件
3: 日本語81万件、英語9万件
一晩待って、計算結果が出ました。
ちゃんと日本語を喋れるようになりました!
perplexityも、どちらかというと日本語が下がり、英語で上がる傾向があるような気がしました。
個人的な手応え: 学習初期に、様々なトークンに触れさせておかないと、局所解に陥るかも(?)
3/12 tokenizerをデカくしてみる
背景
日本語を喋るLLMのtokenizerの語彙サイズは、60kくらいが一つの目安になっています。
一方、2024年に登場したGemmaの語彙は脅威の256kでした。
中国のQwen系も150k
語彙が多いほど、学習token数を減らせる
一方、下手に増やせば良いというものでもないようです
BLOOMは250k
embedding層のサイズが大きすぎて大変だった模様
あんまり評判は高くない印象
どこのサイトか忘れましたが、Gemmaも、日本語の圧縮率は一般的なモデルの1.5倍程度(?)と、そこまで高くない
今回のタスク
これまではvocab sizeを5kでやってたので、ものは試しに、65k, 250kにしてみます。
学習データは3/11と同じです。
語彙の比較
流石に語彙を増やしすぎた気がします。少なくとも、もっと多くの文章でtokenizerを学習させた方が良さそうです。
sentencepiece (unigram)を使用しました。
学習結果
いまいちでした。 (計算は途中で止めました)
65k付近に最適解がありそうです。
ポイント
vocabを増やすと、データセットのtoken数を減らせる
しかし、減る速度はどんどん落ちていく
少なくとも今回のdatasetでは、65k程度のvocabで十分
vocabを増やすと、必要なVRAM量が上昇し、batch sizeを小さくする必要がある
そのせいか、250kではlearning timeが5k条件の二倍程度に。
65kでもglobal batchは小さくなったが、学習tokenが減ったこともあり、1 epochあたりのlearning timeを削減できた
3/13 tokenizerの語彙数で出力を比較する
語彙数が65kのモデル学習(0.3b)が終わったので、出力を語彙数5k, 65kで比較してみます。
日英Wikipediaを学習: 3 Stageに分けてデータセットを配置
1: 日本語9万件、英語9万件
2: 日本語9万件、英語81万件
3: 日本語81万件、英語9万件
結果: perplexityは増えるが、体感の精度はあまり変わらない
語彙数が多い ≒ 予測すべきtokenの選択肢が増える ので、perplexityが増大するのは、想定内の結果かもしれません。
このあたりは結局、学習トークン数を稼ぐしかなさそうです
1文字あたりの出力時間も、 0.005 sec/文字 → 0.004 sec/文字 程度まで削減できました。
今回はwikipediaのようなきれいな文章のみでtokenizerを学習しましたが、mc4など、種々の文章を混ぜたときの語彙の最適値は微妙に変わるかもしれません。 (今後の検討課題)
3/13 雑多なweb文章を学習させる
wikipediaではなく、雑多なweb文章を学習させてみます。
mc4-jaを100万件、wikipedia-enを100万件
全くクリーニングしていません
学習順序やモデルサイズは、3/11と同じです。
tokenizerは今回のデータセットで再学習しました。
mc4-jaは、そのままでは目も当てられないほど、汚いテキストが多量に含まれています(こちら)。
それをそのまま学習させるという作業をしてみました。
結果: わりと日本語を喋れました。
ただし、perplexityは高めの印象です。
ゴミ情報が多いからなのか、それとも、mc4の情報が多彩だからなのかは、なんともわかりません
広告っぽい単語の羅列をいれると、広告サイト風のテキストが出てきます。
感想: 大規模言語モデルは賢いと思いました。
3/18 ジャンルごとに継続学習してMoEとして推論する
以下のステージにわけてモデルを学習させました(件数は概算, 約6b tokens)。
Stage 0: ランダム
日本語Wiki 3万件、mc4-ja 3万件、英語Wiki 3万件
Stage 1: 英語Wiki
日本語Wiki 3万件、mc4-ja 3万件、英語Wiki 80万件
Stage 2: 日本語雑多(mc4)
日本語Wiki 3万件、mc4-ja 80万件、英語Wiki 3万件
Stage 3: 日本語Wiki
日本語Wiki 80万件、mc4-ja 3万件、英語Wiki 3万件
モデル
1 bのモデルにしました
某先生のサーバーをお借りしました。ありがとうございます!
A100 x8 で1日弱でおわりました。
少しズレはありますが、stage 2,3,4に対応するcheckpointを保存して、独立したモデルとして使います
推論
Stage 2,3,4のモデルの中から、最も予測性能が高いものを選んで回答を生成させます
入力文章に対するperplexityを計算し、一番小さなモデルを使うアルゴリズムを適用します
perplexityは、入力文章そのものをモデルに予測させた際の「予測誤差」です。
perplexityが小さい ≒ その文章と親和性が高い ≒ 回答精度も期待できる というロジックです
実装メモはこちら
結果
いくつかの入力に対して、推論させました。
model id
0: 英語特化(stage 1)
1: 雑多な日本語特化(stage 2)
2: きれいな日本語特化(stage 3)
PPL List
各モデルのinputに対するppl
ポイント
「今日は晴れてるから」、「ブログを書きました」のような、wikipediaへの記載がなさそうな文章については、Stage 2のモデル(雑多な日本語特化)が選ばれました。
「地球温暖化」のような、お硬いトピックについては、Wikipediaを読んだ直後のStage3のモデルが選ばれました。
予想外だったのは、「global warming」のような英語の入力に対しては、英語を学んだ直後(stage 1)ではなく、日本語を重点的に学んだstage 3以降のモデルが選ばれたことです
stage 2,3でも英語は少しだけ学ばせてますが、perplexityがStage 1,2,3の順に顕著に下がっていることを感が見えると、
日本語を学ぶことで英語の能力も一応は向上しているのかもしれない?と思いました。
ただ、この規模のモデルで、知識転移が起きる印象はあまりないです
1 bモデルに対して、6b tokenしか学習させていない点にも注意が必要そうです(Chinchilla 論文以降は、少なくとも20倍は学ばせるのが、定石です)。
文法の共通規則のようなものを学んでいる可能性はあるかもしれません。
3/19 カリキュラム学習&ジャンルごとのモデル切り替え練習
・1bモデルを以下のステージに分けて学習させました。
・前回に比べ、英語や日本語の件数を数倍に増やしています(全部で10b)。
・Stage 2,3,4に時点のモデルをそれぞれid 0,1,2として、入力に対するperplexityを計算しながら、出力を見ました。
・各入力に対する、出力は以下の通り。(boldが、perplexityが最も低い、ベストと判断されたモデルの出力です)
感想:
わりといい感じにモデルを切り替えられました。
基本的には、stageが上がるほど、(当然ながら?)モデルは賢くなるようです。
英語を中心的に学習させた、最初のモデルは、ほぼ使われませんでした。
ただし、mc4にいかにも入っていそうなblog系の内容などでは、model id =1 が選ばれる結果となり、ドメイン特化の有効性を改めて確認できました。
3/24 DeepSpeedのZero Stage 0,1の速度比較
共通条件
パラメータ
model_size: 1.3
num_layers: 24
num_attn_heads: 16
hidden_size: 2048
GPU
A100(80gb) x8
結果
Stage 0: global batchは88が限界
Stage 1: global batchは112が限界
どちらも約1.7 samples/secで、速度にほぼ違いなし。
感想
Stage 2,3では、よりVRAM使用量を削減できるとの噂です。
が、速度面では、 0>1>2>3>3+offload との噂なので、十分にGPUを確保できる場合は、敢えて使う必要はない感じでしょうか、、。
4/2 2.7bの事前学習が終了
概ね、英語wikipedia(360万件)→ CommonCrawl系日本語(1000万件)→日本語wikipedia(120万件)がメインになるような順番でカリキュラム学習させました。
合計で30 btoken程度です。
0.1bに比べて、「雑多な日本語ゾーン」でのlossの下がりが改善されました。もっとモデルサイズを大きくすれば、雑多な日本語を喋れるようになるのでしょうか。
評価結果
以下のcheckpointで保存された3つのモデルの出力を見ることにしました。
model id 0: 24000/199305 step → 英語メイン
model id 1: 180000/199305 → 雑多な日本語メイン
model id 2: 199305/199305 → きれいな日本語メイン
ポイント
1b model with 10b tokenでは無理だった、翻訳タスクに対応できたことに、ちょっと感動しました。
1bモデル: 英語: He is a good man. 日本語: 私は、私の夫は私を愛している。
2.7bモデル: 英語: He is a good man. 日本語: 彼は素晴らしい人です。
学習データ数が極めて少ない、model id 0がperplexity (ppl)的に選ばれる頻度が高いことに驚きました。
一方、pplが大きいはずのmodel1,2の方が、(少なくとも最初の文については)出力がマトモであるようなケースがあります。
model 1,2では、色々な日本語を学びすぎて、逆に、入力文(例: 今日は晴れてるから)をきちんと予測できなくなってしまったのでしょうか。謎は深まるばかりです。
input: 今日は晴れてるから
・model id 0 (perplexity=239): 今日は晴れてるから、雨が降らないと困る。 でもね~・・・この前は雨が降ってなかったのにな~。 【楽天市場】10%OFF
・model id 1 (perplexity=957): 今日は晴れてるから、ちょっと散歩にでも行こうかな。 【楽天市場】購入者さんの【送料無料】【2ケースセット】(北海道・沖縄は別途送料必要)サントリー天然
・model id 2 (perplexity=6772): 今日は晴れてるから、雨の心配はなさそう。 The Battle of the River Plate was a naval battle fought in April and May, during World War I. It
4/6 2.7bモデルの学習データの依存性
日英wiki,NHKニュース, 青空文庫だけを学習した、「温室LLM」を新規に作ってみました。
モデル 1: 英語wiki + 雑多な日本語モデル (前回までに構築)
モデル 2: 追加で日本語wikiを学習 (前回までに構築)
モデル 3: 上述の構成でフルスクラッチ
モデル0、1の学習トークン数が30b程度であるのに対し、モデル2は、わずか2.8bに過ぎない点にも注目です。
学習結果
train lossだけ見ると、新規モデルも遜色ない結果となりました。
実際の出力
所感
学習したトークン数(モデル1,2は30b、モデル3は2.8b token)で総合性能に大差はないように見える
このサイズのモデルの言語能力は、わりと初期段階で決まる?
完全ではないが、perplexityが低いモデルほど、良い回答を出す傾向があるように見える
雑多なテキストの後、きれいなテキストを学習させたモデル2(ある種のカリキュラム学習)は、perplexityが高い傾向にあり、回答内容も劣化している印象
例えば、日本語の後にThe Battle of the River …という謎の英文が、頻度高く入るようになってしまっている
モデルが混乱しているかも?
スラング系の表現を学んでいない「温室モデル」(model 3)は、カジュアル表現に対応できない
例: 地球温暖化はマジでやばいきんまんが起こっている。2014年8月、第3弾『おむすびまんとたまごの国』が発売。
(続く)
この記事が気に入ったらサポートをしてみませんか?