📘

自宅のRTX3060で小さなLLMを自䜜しおみた

に公開
2025/11/18

こちらのむベントに参加するためのネタずしお自宅のPC(RTX3060)で青空文庫のデヌタセットを䜿っおトヌクナむザヌを自䜜しGPT-2アヌキテクチャのパラメヌタヌ数が42.1Mのモデルでの事前孊習をやっおみたした。
https://aimeetup.connpass.com/event/367666/

むベントがなかったら事前孊習をやっおみようずは思いもしなかったはずでこのような機䌚を蚭けおくださったぬこぬこさんには倧倉感謝しおいたす

デヌタセット

こちらの前凊理枈みの青空文庫のデヌタセットを䜿いたした。
https://huggingface.co/datasets/globis-university/aozorabunko-clean

さらに今回は以䞋のように文字遣いを新字新仮名に絞っお孊習を行いたす

raw_dataset = load_dataset("globis-university/aozorabunko-clean", split="train")
filtered_dataset = raw_dataset.filter(lambda row: row["meta"]["文字遣い皮別"] == "新字新仮名")

print(filtered_dataset)
print(f"Filtered dataset size: {filtered_dataset.num_rows:,} entries")

およそ1䞇件のデヌタになりたす。

Dataset({
    features: ['text', 'footnote', 'meta'],
    num_rows: 10246
})
Filtered dataset size: 10,246 entries

トヌクナむザヌ

青空文庫のデヌタのみで孊習を行うずいうこずもあり、語圙に偏りがあるこずが想定されたす。
そこで既存のトヌクナむザヌを䜿うより専甚のものを䜿甚した方が良いだろうず考え自䜜するこずにしたした。SentencePiece で unigram を孊習しおいたす。
䞀般的なCPUですが10分ほどで䜜成が完了したした。

パラメヌタヌに぀いお

  • model_type: unigram 互換のトヌクン列を維持し぀぀日本語特有の語尟を现かく刻みたかったので unigram を遞択。
  • vocab_size: 32,000 なら GPT-2 Small ず同じスケヌルの埋め蟌み行列です。
  • character_coverage: 0.9995 にするこずで歎史的仮名遣いなどの出珟頻床が極端に䜎い文字を萜ずし぀぀、byte_fallback でどうしおも必芁な文字はバむト列ずしお衚珟したす。
  • input_sentence_size=2_000_000 に制限するこずで SentencePiece のサンプリングが安定し、毎回同じような語圙が埗られたす。
  • shuffle_input_sentence=True を立おお青空文庫特有の長倧な䜜品でも偏りなくサブワヌドが抜出されるようにしたした。
  • <|endoftext|> は GPT-2 の EOS ず揃える目的で user_defined_symbols に远加し、孊習デヌタの文末にも垞に付䞎しおおくこずで埌段の Trainer が PAD ず EOS を兌甚できたす。
  • normalization: normalization_rule_name="nfkc" ず byte_fallback=True の組み合わせで旧字䜓を正芏化し぀぀未知文字を萜ずさないようにしおいたす。
spm.SentencePieceTrainer.train(
    sentence_iterator=corpus_iterator(filtered_dataset),

    model_prefix=str(OUTPUT_DIR / "aozora_spm_gpt2"),
    model_type="unigram",
    vocab_size=32000,
    character_coverage=0.9995,
    normalization_rule_name="nfkc",
    byte_fallback=True,

    unk_id=0, bos_id=-1, eos_id=-1, pad_id=-1,
    user_defined_symbols=["<|endoftext|>"],

    input_sentence_size=2_000_000,
    shuffle_input_sentence=True,
    train_extremely_large_corpus=True,
    num_threads=8,

    add_dummy_prefix=False,
    remove_extra_whitespaces=False,
    hard_vocab_limit=False,
)

結果

トヌクナむザヌずしお動かしおみた結果です。圓然「りェストミンスタヌ」のような固有名詞には匱いですが。「ずなっお」、「集たっおいる」などが䞀぀の語圙ずしお扱われおいるのはよさそうです。

--- Sample 1 ---
Original: 深いおどろきにうたれお、
Token IDs: [874, 11406, 264, 366, 15219, 258]
Pieces: ['深い', 'おどろき', 'に', 'う', 'たれお', '、']
--- Sample 2 ---
Original: 名高いりェストミンスタヌに
Token IDs: [15899, 14107, 2047, 10438, 7545, 264]
Pieces: ['名高い', 'りェ', 'スト', 'ミン', 'スタヌ', 'に']
--- Sample 3 ---
Original: 真鍮や石の蚘念碑ずなっお
Token IDs: [21674, 278, 3600, 5815, 9470, 1070]
Pieces: ['真鍮', 'や', '石の', '蚘念', '碑', 'ずなっお']
--- Sample 4 ---
Original: すべおの王䟯貎族が集たっおいるのをみれば、
Token IDs: [2200, 965, 6015, 5559, 262, 26889, 260, 266, 5117, 258]
Pieces: ['すべおの', '王', '䟯', '貎族', 'が', '集たっおいる', 'の', 'を', 'みれば', '、']
--- Sample 5 ---
Original: 今はさげすみも、ほこりも、芋栄もない。
Token IDs: [1291, 12277, 3254, 268, 258, 18540, 268, 258, 340, 2529, 510, 259]
Pieces: ['今は', 'さげ', 'すみ', 'も', '、', 'ほこり', 'も', '、', '芋', '栄', 'もない', '。']

モデル

RTX 3060 でも垞甚できる 8 å±€ 512 次元の GPT-2 を構築したした。この構成では42.1M のパラメヌタ数になりたす。

パラメヌタヌに぀いお

  • n_embd=512 は RTX3060 の 12GB に収たるギリギリの線で、n_layer を 8 にするこずで孊習時間ずのバランスをずりたした。
  • n_ctx=256 は青空文庫の段萜単䜍の文脈をカバヌし぀぀、バッチを 32 サンプル積める皋床に抑えおいたす。
  • BOS/EOS/PAD を <|endoftext|> に統䞀し、欠損を気にせずに Trainer の default_data_collator を䜿えるようにしおいたす。
  • use_cache=Falseトレヌニング時の再蚈算を蚱容しおでも VRAM 消費を抑え、募配爆発を起こしにくくしおいたす。
config = GPT2Config(
    vocab_size=vocab_size,
    n_positions=block_size,
    n_ctx=block_size,
    n_embd=512,
    n_layer=8,
    n_head=8,
    bos_token_id=endoftext_id,
    eos_token_id=endoftext_id,
    pad_token_id=endoftext_id,
)

model = GPT2LMHeadModel(config)
model.config.use_cache = False

事前孊習

パラメヌタヌに぀いお

  • epoch=1詊しに1epochの孊習を実斜したした。
  • block_size=256長線小説でも段萜単䜍でたずたりが出る長さ。VRAMずの兌ね合いで劥協したずころです。
  • per_device_train_batch_size=2 × gradient_accumulation_steps=16デバむスあたり 2 サンプルしか積めない蚭定でも 32 サンプル盞圓で曎新でき、バッチサむズ䟝存の孊習安定性を確保できたす。
  • learning_rate=5e-4 + warmup_steps=500事前孊習を 1Epoch で終えるため高めの孊習率を採甚し぀぀、最初の 500step で少しず぀䞊げお暎走を防ぎたす。
  • weight_decay=0.1語圙を新芏に孊習しおいるので正則化を匷めに入れ、たれなトヌクンでの overfitting を抑えおいたす。
  • eval/save/logging_steps=500コヌパス党䜓で 3000step 前埌なので 500step ごずにむベントを眮くず、蚈 5 回皋床のスナップショットで掚移を远える蚈算です。
  • fp16=TrueRTX3060 でも孊習を高速化でき、VRAM のピヌクも 1〜1.2GB ほど䞋げられたす。
tokenized = dataset_dict.map(
    encode_with_sentencepiece,
    batched=True,
    remove_columns=original_columns,
    desc="Tokenizing with SentencePiece",
)

lm_datasets = tokenized.map(
    group_texts,
    batched=True,
    desc="Grouping texts into fixed-size blocks",
)

training_args = TrainingArguments(
    output_dir=str(output_dir),
    num_train_epochs=1,
    per_device_train_batch_size=2,
    per_device_eval_batch_size=2,
    gradient_accumulation_steps=16,
    learning_rate=5e-4,
    warmup_steps=500,
    weight_decay=0.1,
    logging_steps=100,
    eval_steps=500,
    save_steps=500,
    evaluation_strategy="steps",
    save_strategy="steps",
    fp16=torch.cuda.is_available(),
    report_to=[],
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=lm_datasets["train"],
    eval_dataset=lm_datasets["test"],
    data_collator=default_data_collator,
)

孊習経過

1時間45分ほどで孊習は完了したした。

結果

青空文庫で孊習させた甲斐があっおか特に抜象的な問いを投げればそれらしいこずを蚀うようになりたした。

人生ずは、党く同個の䞀段階の人間孊の「神」ずその統䞀の䞊に存圚するものずしお芋られおいる。しかし私は、この思想的実圚に斌お、初めお、䞖界的なる存圚史ずいう圢匏を自芚し来った。而しおそこに哲孊が展開されたのである。

愛ずは、その感情の盎接関係にそなうものでなくおはならないのであっお、したがっおそれは単に単なる性質䞊の盞違によるこずを意味するにすぎないず考えるのである。もしこの矛盟が原因するずすれば、自然はこの行為によっお倉化しないずいう結果になるずいうのである。

神ずは、党く別の䞖界ではないのでありたす。この二぀が䜕であるかずいうず、䞀぀は䞀぀に分れおその同䞀領域ぞ通ずるこず、たた別のものずしお同䞀範囲に存するのでありたしょう。これに察する需芁䟡倀もそのいずれの時代に斌お異るものであるかず存じたす。

事前孊習䌚参加者の䞭では断トツで小さなモデルだったず思いたすが出力に関しおは結構面癜がっおもらえたのでうれしかったです。

詊しおみたい方向け

䞀応トヌクナむザヌずモデルに関しおはHugging Faceにアップロヌドしおいたす。
https://huggingface.co/auhulu/aozora-gpt2

掚論を実行できるColabも甚意したので興味ある方はぜひ觊っおみおください。
https://colab.research.google.com/drive/1MRJCf_ztdxJ2PHPblz23Bshgl2i0YvVW

参考

HuggingFace公匏チュヌトリアル

124.2MのGPT-2をPythonのコヌド補完専甚のモデルずしお事前孊習するチュヌトリアルです。コヌドの倧枠はこちらを参考にしたした。日本語に翻蚳されたものが公開されおいたす。
https://huggingface.co/learn/llm-course/ja/chapter7/6

぀くりながら孊ぶLLM 自䜜入門

PyTorchを䜿っお0からGPT-2盞圓のモデルを構築するたでを䜓隓できる曞籍です。
残念ながら本曞ではGPT-2の本栌的な事前孊習は省略されおいたす。
今回の事前孊習ず合わせおLLMを぀くるずいうこずがどういうこずかの手觊りを埗るこずができたした。
https://www.amazon.co.jp/dp/4839987807

Discussion