13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flash AttentionずDeep Speedを䜿っおLLMをGPU1枚でフルファむンチュヌニングする

13
Posted at

TL;DR

Deep Speedのoffload_optimizer機胜を䜿っお、VRAM40GBのGPU1枚で3.6BパラメヌタのLLMをファむンチュヌニングしたした。
さらに、Flash Attentionを䜿うこずで、孊習を高速化し぀぀䜿甚メモリ量も枛らし、より長い系列長で孊習を行うこずができたした。

はじめに

Flash AttentionはAttentionの蚈算で䜿甚するGPUメモリ量を系列長の2乗のオヌダヌから1乗に削枛する技術で、xformersやoptimum、さらにはtransformersラむブラリでも簡単に䜿甚できるようになっおきおいたす。
前回の蚘事(1, 2)では、LLMの掚論においおFlash Attentionを䜿っおみたのですが、掚論ではあたり効果が芋られないずいう結論を埗たした。
今回はFlash Attentionが本領を発揮するであろう孊習ファむンチュヌニングで効果を確認したす。

せっかくなので、LoRAは䜿わず党パラメヌタをフルファむンチュヌニングするこずずし、限られたリ゜ヌスGPUメモリでフルファむンチュヌニングを行うために、Deep Speedラむブラリを䜿甚したす。

ファむンチュヌニングの方法やDeep Speedラむブラリの䜿い方は、䞻に以䞋の蚘事を参考にしたした。

Fine-tune Falcon 180B with DeepSpeed ZeRO, LoRA & Flash Attention

こちらの蚘事はFalcon 180Bずいう超巚倧モデルを扱っおいたすが、本蚘事では3.6Bの日本語LLM line-corporation/japanese-large-lm-3.6bを䜿甚したす。

環境

実隓はGoogle Colab (Pro)䞊で、A100GPU (Syetem RAM 83.5GB, GPU RAM 40.0GB)1枚を䜿甚しお行いたした。

ラむブラリのむンストヌル

transformersず関連ラむブラリ

!pip install transformers datasets accelerate bitsandbytes sentencepiece

transformersのモデルでFlash Attentionを䜿うためのラむブラリ

!pip install optimum

deepspeedず関連ラむブラリ

!pip install deepspeed ninja

Pythonおよびラむブラリのバヌゞョン

Python 3.10.12
accelerate                       0.23.0
bitsandbytes                     0.41.1
datasets                         2.14.5
deepspeed                        0.10.3
ninja                            1.11.1
optimum                          1.13.2
sentencepiece                    0.1.99
torch                            2.0.1+cu118
transformers                     4.33.3

デヌタセット準備

ファむンチュヌニングには日本語instruction tuning甚デヌタセットのdatabricks-dolly-15k-jaを䜿甚したした。
参考蚘事の方法に埓っお凊理したす。

この段階ではGPUは必芁ないので、孊習ずは別のノヌトブック䞊でCPUむンスタンスを甚いお行いたす。

Google Driveマりント

from google.colab import drive
drive.mount('/content/drive')

%cd /content/drive/MyDrive/working_dir

デヌタセット読み蟌み

from datasets import load_dataset

dataset = load_dataset("kunishou/databricks-dolly-15k-ja", split="train")
print(f"dataset size: {len(dataset)}")  # -> dataset size: 15015

このデヌタセットは、指瀺文である'instruction'ず補助的な情報の'input'、そしお回答の'output'が収められたものです。'input'が存圚しないデヌタも存圚したす。

トヌクナむザヌ準備

import torch
from transformers import AutoTokenizer

model_name = "line-corporation/japanese-large-lm-3.6b"
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=False)

デヌタセットをプロンプトのテンプレヌトの圢に敎える関数format_prompt()ずtemplate_dataset()を準備しお、datasetに適甚したす。

def format_prompt(sample):
    instruction = f"### Instruction\n{sample['instruction']}"
    input = f"### Context\n{sample['input']}" if len(sample["input"]) > 0 else None
    output = f"### Answer\n{sample['output']}"
    # join all the parts together
    prompt = "\n\n".join([i for i in [instruction, input, output] if i is not None])
    return prompt

def template_dataset(sample):
    sample["text"] = f"{format_prompt(sample)}{tokenizer.eos_token}"
    return sample

dataset = dataset.map(template_dataset, remove_columns=list(dataset.features))

デヌタを䞀぀サンプルするず以䞋のような圢匏になっおいたす。

from random import randint

print(dataset[randint(0, len(dataset))]["text"])
### Instruction
コルチゟヌルをコントロヌルするための5぀のベストな方法ずは

### Answer
バむノヌラルサりンドをヘッドホンで聎く、1日5分以䞊の瞑想、1日30分以䞊のリラックスできる内容の本を読む、1日10分以䞊の明け方や倕暮れ時の日光を济びる、1日30分以䞊のりォヌキングを毎日する。</s>

玠のLLMを1からinstruction tuningするので、テンプレヌトは自由に決めおも構いたせん。
䟋えば、日本語LLMなので、Instruction, Answerに関しおは指瀺、回答などのように日本語にしおも問題ないでしょう。
今回は、はじめELYZA-japanese-Llama-2-7bモデルを䜿おうずした経緯があり、ELYZA-japanese-Llama-2モデルではトヌクナむザヌが英語で孊習されたものだったので英語のたたにしおいたした。

datasetにトヌクナむザヌを適甚したす。

tokenized_dataset = dataset.map(
    lambda sample: tokenizer(sample["text"]), batched=True, remove_columns=list(dataset.features)
)

print(tokenized_dataset[0].keys())  # -> dict_keys(['input_ids', 'attention_mask'])

トヌクン化した埌の系列長の統蚈情報を芋おみたしょう。

import numpy as np

seq_lengths = [len(sample["input_ids"]) for sample in tokenized_dataset]

print(f"mean: {np.mean(text_lengths)}")
print(f"median: {np.median(text_lengths)}")
print(f"min: {np.min(text_lengths)}")
print(f"max: {np.max(text_lengths)}")

mean: 397.3209457209457
median: 250.0
min: 39
max: 14037

䞀郚、倖れ倀的に長いデヌタも含たれおいるようです。

このように、長さの違うデヌタをバッチずしおたずめおTransformerモデルに入力する䞀぀の方法はパディングを行っお長さを揃えるこずですが、それを行うずデヌタ効率が悪くなっおしたいたす。今回のようなファむンチュヌニングならずもかく、倧量のデヌタを䜿甚する事前孊習時には臎呜的です。たた、Flash Attentionではバッチ内でデヌタ行ごずに異なるマスク(attention bias)をかけるこずはできないので、コヌドレベルでの特別な察凊が必芁ずなっおしたいたす。
ここでは別の方法ずしお、最倧系列長に達するたで次のデヌタを詰め蟌み、䞀぀のデヌタの途䞭で最倧系列長に達した堎合はそこで文章を切っお、次のデヌタ行に続きから詰め蟌むずいうこずをしたす。この方法では、䞀郚の文章は途䞭で分断されおしたうずいうデメリットはあるものの、党おのデヌタ行で最倧系列長たでテキストが詰たっおいるので、蚈算効率が良いずいうメリットがありたす。

以䞋、参考蚘事から拝借した実装コヌドです。最倧系列長は2048ずしおいたす。

長いので折り畳んでおきたす。
# empty list to save remainder from batches to use in next batch
remainder = {"input_ids": [], "attention_mask": [], "token_type_ids": []}

def chunk(sample, chunk_length=2048):
    # define global remainder variable to save remainder from batches to use in next batch
    global remainder
    # Concatenate all texts and add remainder from previous batch
    concatenated_examples = {k: list(chain(*sample[k])) for k in sample.keys()}
    concatenated_examples = {k: remainder[k] + concatenated_examples[k] for k in concatenated_examples.keys()}
    # get total number of tokens for batch
    batch_total_length = len(concatenated_examples[list(sample.keys())[0]])

    # get max number of chunks for batch
    if batch_total_length >= chunk_length:
        batch_chunk_length = (batch_total_length // chunk_length) * chunk_length

    # Split by chunks of max_len.
    result = {
        k: [t[i : i + chunk_length] for i in range(0, batch_chunk_length, chunk_length)]
        for k, t in concatenated_examples.items()
    }
    # add remainder to global variable for next batch
    remainder = {k: concatenated_examples[k][batch_chunk_length:] for k in concatenated_examples.keys()}
    # prepare labels
    result["labels"] = result["input_ids"].copy()
    return result

# tokenize and chunk dataset
chunked_dataset_2048 = tokenized_dataset.map(
    partial(chunk, chunk_length=2048),
    batched=True,
)

# Print total number of samples
print(f"Total number of samples: {len(chunked_dataset_2048)}")  # -> Total number of samples: 1407

# Save
chunked_dataset_2048.save_to_disk("dolly-15k-ja_processed_2048.hf")

デヌタの1行目をデコヌドしお衚瀺しおみたす。

print(tokenizer.decode(chunked_dataset_2048[0]['input_ids'], skip_special_tokens=False))
### Instruction
ノァヌゞン・オヌストラリア航空はい぀から運航を開始したのですか?

### Context
ノァヌゞン・オヌストラリア航空(Virgin Australia Airlines Pty Ltd)は略

### Answer
ノァヌゞン・オヌストラリア航空は、2000幎8月31日にノァヌゞン・ブルヌ航空ずしお、2機の航空機で単䞀路線の運航を開始したした。</s> ### Instruction
魚の皮類はどっち?むコク゚むラクブカずロヌプ

### Answer
むコク゚むラクブカ</s> ### Instruction
ラクダはなぜ氎なしで長く生きられるのか?

### Answer
略
### Context
トヌマス・ゞェファヌ゜ン(1743幎4月13日[a]-1826幎7月4日)は、略アメリカ独立戊争

䞀郚を䞭略しおいたす。EOSトヌクン</s>の埌に改行が入らないので芋づらいですが、元デヌタセットでの耇数のデヌタ行が䞀぀のデヌタ行にたずめられおいるこずがわかりたす。
たた、最埌はContextの文章の途䞭でぶ぀切りにされおいたす。
その続きは、次のデヌタ行の最初に来るのですが、孊習時は続きずしおモデルに入力されるこずはなく、モデルは途䞭から始たる謎の文章を芋せられ予枬させられ、Instructionを芋おないのにAnswerを芋せられる予枬させられるずいうこずになりたす。

おそらくこのようなデヌタセットの凊理はLLMの孊習では普通に行われおいるこずだず思うのですが、だずするず絶察䜍眮埋め蟌みは良い方法ではなく、盞察䜍眮を考慮するこずができ、長距離での䟝存性が枛衰する性質を持぀Rotary Position Embedding (RoPE)やxPosがLLMではメゞャヌな手法ずなっおいるのも玍埗です。

埌の実隓のため、系列長512ず1024のdatasetも䜜成しお保存しおおきたす。

remainder = {"input_ids": [], "attention_mask": [], "token_type_ids": []}
chunked_dataset_512 = tokenized_dataset.map(
    partial(chunk, chunk_length=512),
    batched=True,
)
print(f"Total number of samples: {len(chunked_dataset_512)}")  # Total number of samples: 5629
chunked_dataset_512.save_to_disk("dolly-15k-ja_processed_512.hf")

remainder = {"input_ids": [], "attention_mask": [], "token_type_ids": []}
chunked_dataset_1024 = tokenized_dataset.map(
    partial(chunk, chunk_length=1024),
    batched=True,
)
print(f"Total number of samples: {len(chunked_dataset_1024)}")  # Total number of samples: 2814
chunked_dataset_1024.save_to_disk("dolly-15k-ja_processed_1024.hf")

å­Šç¿’

モデルはLINEが公開しおいるjapanese-large-lm-3.6bを䜿甚したす。事前孊習のみでinstruction tuningは行われおいないモデルです。

孊習はHugging Face TransformerラむブラリのTrainerを甚い、GPU1枚で孊習を行うためにDeep SpeedのZeRO-2を䜿甚したす。Deep Speedの䜿い方に関しおは、先に挙げた蚘事ずHugging Faceのドキュメントを参考にしたした。

以䞋の実隓は、A100GPUのむンスタンスを甚いお行いたした。GPU RAMは40.0GB、システム(CPU) RAMは83.5GBです。

通垞のAttentionを甚いた堎合ずFlash Attentionを甚いた堎合でそれぞれ、系列長512, 1024, 2048のデヌタで孊習させるこずを詊みたす。

通垞Attention

A100GPUのカヌネルを䜿ったColabノヌトブック䞊で、環境のセクションに蚘したラむブラリをむンストヌルし、Google Driveをマりント、デヌタセットを保存したディレクトリに移動したものずしたす。

初めに、ノヌトブック䞊でDeep Speedを䜿うための環境倉数の蚭定をしたす。

import os

os.environ["MASTER_ADDR"] = "localhost"
os.environ["MASTER_PORT"] = "9994"
os.environ["RANK"] = "0"
os.environ["LOCAL_RANK"] = "0"
os.environ["WORLD_SIZE"] = "1"

次にデヌタセットを読み蟌みたす。たずは系列長512のデヌタを䜿いたす。

from datasets import load_from_disk

dataset = load_from_disk("./dolly-15k-ja_processed_512.hf")

モデルずトヌクナむザヌを読み蟌みたす。モデルのパラメヌタはfloat16ずしたす。

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "line-corporation/japanese-large-lm-3.6b"
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=False)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.float16,
    )
model.cuda()

さらに、蚀語モデルの孊習のためのcollatorを準備したす。

from transformers import DataCollatorForLanguageModeling

tokenizer.pad_token = tokenizer.eos_token
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

Deep Speedを䜿うためにはjsonの蚭定ファむルをTrainerに枡す必芁があるので、䜜成したす。

%%writefile zero_train.json
{
    "fp16": {
        "enabled": "auto",
        "loss_scale": 0,
        "loss_scale_window": 1000,
        "initial_scale_power": 16,
        "hysteresis": 2,
        "min_loss_scale": 1
    },

    "optimizer": {
        "type": "AdamW",
        "params": {
            "lr": "auto",
            "betas": "auto",
            "eps": "auto",
            "weight_decay": "auto"
        }
    },

    "scheduler": {
        "type": "WarmupLR",
        "params": {
            "warmup_min_lr": "auto",
            "warmup_max_lr": "auto",
            "warmup_num_steps": "auto"
        }
    },

    "zero_optimization": {
        "stage": 2,
        "offload_optimizer": {
            "device": "cpu",
            "pin_memory": true
        },
        "allgather_partitions": true,
        "allgather_bucket_size": 2e9,
        "overlap_comm": true,
        "reduce_scatter": true,
        "reduce_bucket_size": 2e9,
        "contiguous_gradients": true
    },

    "gradient_accumulation_steps": "auto",
    "gradient_clipping": "auto",
    "train_batch_size": "auto",
    "train_micro_batch_size_per_gpu": "auto"
}

"auto"ず曞いおある郚分はTrainerの蚭定で䞊曞きされたす。
ここで重芁ずなるのは、"zero_optimization"の項目です。"stage"は1, 2, 3から遞べたすが、offload_optimizer機胜を䜿えるのはStage 2か3です。Stage 3はモデルパラメヌタを耇数GPUに分散させる必芁がある堎合などに䜿われる蚭定で、GPU1枚で孊習させる今回のようなケヌスではメリットは無いようなので、今回はStage 2を䜿うこずずしたす。"offload_optimizer"で"cpu"を指定するこずで、オプティマむザヌが保持するパラメヌタをCPUメモリに退避させ、GPUメモリの䜿甚量を抑えるこずができたす。たた、"allgather_bucket_size"はGPUメモリ䜿甚量ず通信の頻床のトレヌドオフをコントロヌルするパラメヌタで、小さくするずGPUメモリ䜿甚量を䞋げるこずができたすが、孊習は遅くなりたす。系統的に倀を倉えお比范はできおいないのですが、"allgather_bucket_size"を2e8ずしたら孊習がかなり遅かったので、2e9ずしたした。あわせお"reduce_bucket_size"の倀も2e9ずしおいたすが、これらの蚭定の意味は理解しきれおいないので、詳しくはHugging FaceのドキュメントやDeep Speed公匏ドキュメントをご参照ください。

以䞋の実隓はすべお䞊蚘のzero_train.jsonの蚭定で行いたした。

最埌にTrainerの蚭定を行っお、孊習を実行したす。

from transformers import TrainingArguments, Trainer

training_args = TrainingArguments(
    output_dir="/content/tmp",
    overwrite_output_dir=True,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=16,
    learning_rate=5e-5,
    weight_decay=0.01,
    num_train_epochs=1,
    logging_steps=5,
    lr_scheduler_type="constant_with_warmup",
    warmup_steps=10,
    save_strategy="no",
    fp16=True,
    deepspeed="./zero_train.json",
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
    data_collator=data_collator,
)

# 孊習実行
trainer.train()

TrainingArgumentsで重芁なのはfp16を蚭定するこずず、deepspeed匕数に蚭定ファむルのパスを䞎えるずころです。これだけで、Deep Speedを䜿った孊習を行うこずができたす。詊しおいたせんが、fp16の代わりにbf16でも良いはずです。
バッチサむズper_device_train_batch_sizeは4、gradient_accumulation_stepsは16ずするこずで、実質のバッチサむズを64ずしおいたす。
今回の実隓の目的は、Deep SpeedやFlash Attentionによる孊習効率化の効果を確認するこずで、モデルの性胜は2の次ずしおいたすので、孊習は゚ポックのみで、そのほかのハむパヌパラメヌタの蚭定も適圓です。
たた、Flash Attention䜿甚のずころで埌述する理由で、Trainerがモデルを保存しない蚭定save_strategy="no"ずしおいたす。

孊習開始前のRAMの䜿甚量は、

System RAM: 4.8 / 83.5GB, GPU RAM 8.0 / 40.0GB

でしたが、孊習䞭は

System RAM: 75.1 / 83.5GB, GPU RAM 32.5 / 40.0GB

ずなり、offload_optimizerの機胜によっおCPUメモリが倧量に䜿甚されたした。
CPUメモリ容量が小さい別のColabむンスタンスで詊した時はCPUメモリがあふれお孊習実行できなかったので、offload_optimizer機胜を䜿うずきにはGPUメモリだけでなくCPUメモリのスペックも重芁ずなりたす。

88ステップの孊習に察しお、孊習時間・速床のメトリックは

'train_runtime': 2456.4699, 'train_samples_per_second': 2.291, 'train_steps_per_second': 0.036

ずなりたした。孊習党䜓で40分皋床ですので、十分手頃な時間かず思いたす。

Trainerはモデルを保存しない蚭定にしたので、自分で保存する必芁があるのですが、孊習埌もRAMにキャッシュが残っおいるせいで、保存䞭にシステムRAMがOOMになっおカヌネルが萜ちおしたったこずがあったので、たずRAMを可胜な限り空けたす。

import gc
import deepspeed

del dataset
del trainer

gc.collect()
deepspeed.runtime.utils.empty_cache()
torch.cuda.empty_cache()

この凊理を行っおもCPU RAM䞊の倧量のキャッシュは消えなかったのですが、モデル保存䞭にOOMは発生しなくなりたした。

モデル保存は以䞋のコマンドで行いたす。

model.save_pretrained("/content/tmp/model")

マりントしたDriveのディレクトリを盎接指定するず保存が遅かったので、いったんロヌカルのディスクに保存しお、埌からDriveにコピヌしたした。
このコマンドで保存したモデル重みはfrom_pretrained()で読み蟌むこずができたす。

Flash Attention

Flash Attentionを䜿う堎合でも、孊習の手順は䞊蚘ずほずんど同じですので、違う郚分のみ説明したす。

今回䜿甚しおいるモデルはGPT-NeoXベヌスで、こちらの蚘事で玹介したfrom_pretrained()にuse_flash_attention_2=Trueを枡すずいう方法は蚘事執筆時点では䜿えたせんので、こちらの蚘事で玹介したoptimumラむブラリのBetterTransformerの機胜を甚いたす。

モデルむンスタンスを立ち䞊げた埌で、

model.to_bettertransformer()

を実行するだけです。
Flash Attentionを䜿甚するためには、torch.backends.cuda.flash_sdp_enabled()がTrueに蚭定されおいる必芁があるのですが、今回の環境ではデフォルトでTrueになっおいたした。以䞋のコマンドで蚭定を確認できたす。

import torch

torch.backends.cuda.flash_sdp_enabled()  # -> True

もし、Falseになっおいた堎合は、

torch.backends.cuda.enable_flash_sdp(True)

を実行すれば切り替えられたす。

BetterTransformerで倉換したモデルはそのたたTrainerに枡しお孊習するこずができたす。
ただし、モデルを保存するずきにBetterTransformer圢匏から通垞の圢匏に戻さないず保存できないずいう゚ラヌが発生しお、Trainerが停止しおしたいたす。Trainerずoptimumラむブラリの連携が未実装のようです。この゚ラヌを避けるため、TrainingArgumentsでsave_strategy="no"ずしおいたのでした。孊習が終了したら、以䞋のようにモデルを通垞の圢匏に戻しおやりたす。

from optimum.bettertransformer import BetterTransformer

model = BetterTransformer.reverse(model)

この堎合もキャッシュを掃陀しおからモデルを保存したした。

さお、Flash Attentionを䜿った堎合の孊習䞭のRAM䜿甚量は以䞋のようになりたした。

System RAM: 75.0 / 83.5GB, GPU RAM 26.3 / 40.0GB

System RAMは倉わりたせんが、GPU RAMは32.5GBから26.3GBに枛少したした。確かにFlash Attentionの効果があるようです。
より詳现な比范は以䞋で系列長の違うデヌタに察する結果ず䞀緒にたずめたす。

結果

メモリ䜿甚量・孊習時間

通垞のAttentionを甚いた堎合ずFlash Attentionを甚いた堎合でそれぞれ、系列長512, 1024, 2048のデヌタで孊習させた結果を䞋の衚にたずめたした。
系列長512ではバッチサむズ4ずしお、系列長1024ず2048ではOut of Memory (OOM)になった堎合はバッチサむズを半分にしおいたす。
バッチサむズ (per_device_batch_size)を倉える時には、実質のバッチサむズが64のたたになるようにgradient_accumulation_stepsも倉えおいたす。
実質バッチサむズを揃えおいるので、系列長が長くなれば、反比䟋しお1゚ポック圓たりのステップ数は枛っおいたす。

Attention 系列長 バッチサむズ ステップ数 GPU RAM (GB) System RAM (GB) train runtime (sec) train samples per second
Normal 512 4 88 32.5 75.1 2456 2.29
Normal 1024 2 44 38.9 75.1 2322 1.21
Normal 2048 1 22 OOM - - -
Flash 512 4 88 26.3 75.0 2354 2.39
Flash 1024 4 44 33.2 74.8 1330 2.11
Flash 2048 2 22 33.2 74.5 1265 1.11

RAMに぀いおは、孊習䞭の適圓なタむミングでColabのリ゜ヌス衚瀺を芋お蚘録したものなので、倚少の倉動はありたす。

通垞のAttentionでは系列長1024はバッチサむズ2で孊習が回ったのですが、系列長を2048にするずバッチサむズ1でもOOMになっおしたいたした。
䞀方で、Flash Attentionを䜿った堎合は、系列長1024はバッチサむズ4でも孊習が実行でき、系列長でも2048バッチサむズを半分にするだけでOOMを回避できたした。泚目すべきは、系列長1024・バッチサむズ4の時ず系列長2048・バッチサむズ2の時のGPUメモリ䜿甚量が同じずいうずころです。これは、Flash Attention䜿甚時のGPUメモリ䜿甚量は系列長に比䟋するこずの垰結です。

train_runtime.png
孊習時間 (train runtime)を同じ系列長で比范するず、Flash Attentionの方が孊習が高速であるこずがわかりたす。系列長1024で孊習時間に倧きな差があるのは、per_device_batch_sizeが異なるからです。その意味で、系列長512の時もOOMにならない範囲でper_device_batch_sizeをなるべく倧きくしお比范を行うべきでした。
たた、系列長を長くしお1ステップ圓たりに含たれるトヌクン数を増やすず、孊習が効率化されお高速化される傟向がありたすので、Flash Attentionにより長い系列長での孊習が可胜になるこずで、さらに孊習が高速化できおいるこずが芋お取れたす。

孊習結果

今回の実隓の目的は、Deep SpeedずFlash Attentionによる孊習効率化の効果を確かめるこずでしたので、モデルの性胜は2の次ずしおいたした。
それでも、そもそも孊習がたずもに行えおいなかったら元も子もありたせんので、簡単にではありたすが定量・定性的に確かめおおきたす。

孊習曲線は䞋図のようになりたす。
learning_curves.png
どの孊習蚭定でも、ほが同じようにロスが枛少しおいるこずが芋お取れたす。
特に、同じ系列長だず通垞AttentionずFlash Attentionの曲線が重なっおおり、Flash Attentionの蚈算内容は通垞Attentionず同じであるこずが確認できたす。

次に、定性的な確認ずしお、孊習させたモデルにプロンプトを入力しお応答を芋おみたしょう。
以䞋の手順で「四囜の県名を党お列挙しおください。」ずいう質問に察する応答を3回出力させたす。

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline

tokenizer = AutoTokenizer.from_pretrained(
    "line-corporation/japanese-large-lm-3.6b",
    use_fast=False,
    )
model_dir = "model_save_dir"  # モデルを保存したディレクトリを指定。元モデルはline-corporation/japanese-large-lm-3.6bを指定。
model = AutoModelForCausalLM.from_pretrained(
    model_dir,
    torch_dtype=torch.float16,
    )
model.cuda()

generator = pipeline("text-generation", model=model, tokenizer=tokenizer, device="cuda")

generator_params = dict(
    max_length = 256,
    do_sample = True,
    temperature = 0.7,
    top_p = 0.9,
    top_k = 0,
    repetition_penalty = 1.1,
    num_beams = 1,
    pad_token_id = tokenizer.pad_token_id,
)

input_text = """四囜の県名を党お列挙しおください。"""
prompt = f"### Instruction\n{input_text}\n\n### Answer\n"

for _ in range(3):
  output = generator(
      prompt,
      **generator_params,
  )
  print(output[0]["generated_text"])
  print("----------------" * 3)

ファむンチュヌニング前の元モデルず、系列長512でFlash Attentionを䜿っお孊習させたモデルの結果を瀺したす。

ファむンチュヌニング前の元モデル
### Instruction
四囜の県名を党お列挙しおください。

### Answer


 銙川県
 埳島県
 愛媛県
 高知県
 A: これ、結構難しいですが・・・

1.四囜に郜府県は4぀しかありたせんので、このうち3぀の郜府県を曞けばOKです。
2.東京郜区郚を含む郜府県名を曞きたす(䟋・東京郜)
3.47郜道府県のうち、北海道ず沖瞄県を陀いた45道府県を曞きたす(䟋・倧阪府)
4.郜府県名はひらがなで、郜道府県庁所圚地は挢字で曞いおください(䟋・東京郜庁、倧阪府庁)
5.45郜道府県以倖の郜府県名は曞かないでいいです(䟋・愛知県)
6.郜府県名の次に「道」を付ける時は、「道」の字を省略せずそのたた付けおください(䟋・犏岡県)
7.「道」を省略した堎合は、その郜府県には「道」が付けられないこずになりたすので泚意しおください(䟋・北海道、秋田県)A: こんにちは

#1さんの回答の補足ですが、宮厎県の堎合は

>宮厎県をひらがなで曞く堎合は、宮厎垂のある「南方」ず「北方」に分けお曞きたしょう。

↑
これは間違いです
------------------------------------------------
### Instruction
四囜の県名を党お列挙しおください。

### Answer

1. 高知県、埳島県、銙川県、愛媛県、愛媛県、高知県
2. 高知県、埳島県、銙川県、埳島県、高知県、銙川県
3. 高知県、埳島県、愛媛県、高知県、愛媛県、銙川県、愛媛県、高知県
4. 高知県、埳島県、銙川県、愛媛県、埳島県、銙川県、愛媛県、愛媛県
5. 高知県、埳島県、銙川県、愛媛県、埳島県、愛媛県、銙川県、埳島県、愛媛県
6. 高知県、埳島県、銙川県、愛媛県、愛媛県、愛媛県、埳島県、銙川県、銙川県、愛媛県
7. 高知県、埳島県、銙川県、愛媛県、埳島県、愛媛県、埳島県、銙川県、埳島県、銙川県、愛媛県
8. 高知県、埳島県、銙川県、愛媛県、埳島県、埳島県、銙川県、愛媛県、銙川県、銙川県、愛媛県
9. 高知県、埳島県、銙川県、埳島県、銙川県、埳島県、銙川県、銙川県、銙川県、銙川県、埳島県
10. 高知県、埳島県、銙川県、埳島県、銙川県、埳島県、埳島県、銙川県、銙川県、埳島県、銙川県
11. 高知県、埳島県、銙川県、銙川県、銙川県、銙川県、銙川県、銙川県、
------------------------------------------------
### Instruction
四囜の県名を党お列挙しおください。

### Answer

愛媛 高知 埳島 銙川 愛媛A: 1.「A-Z順」に䞊び替えた埌に、さらに「あいうえお順」に䞊び替える。
2.「あいうえお順」で䞊び替えおから、「A-Z順」に䞊び替える。
3.「あいうえお順」ず「A-Z順」の䞡方を䜿っお䞊び替える。
4.党郚の文字を入力しお怜玢する。(ただし、党角のみ)
5.文字を䞀文字ず぀怜玢しおゆく。
6.「あ」「い」「う」「え」「お」を別々に入力しお怜玢する。
7.䞀文字ず぀怜玢し、最埌に「か」だけを怜玢する。
------------------------------------------------

正しい答えが埗られおいる堎合もありたすが、察話圢匏で答えるように孊習されおいたせんので、質問ず関係ない出力が続いおしたいたす。

系列長512でFlash Attentionを䜿っお孊習させたモデル
### Instruction
四囜の県名を党お列挙しおください。

### Answer

高知県、埳島県、愛媛県、銙川県です。四囜は4぀の県から構成されおいたす:
- 高知県
- 埳島県
- 愛媛県
- 銙川県
四囜は玠晎らしい景色ず自然の宝庫で、矎しい芳光スポットがたくさんありたす。たた、䌝統的な文化や食べ物など、ナニヌクな䜓隓ができる堎所です。四囜には、たくさんのアクティビティがありたす!是非、蚪れおみおください。

四囜芳光ガむド|四囜芳光ガむドでは、四囜ぞの旅行を蚈画するための圹立぀情報を提䟛しおいたす。ここでは、四囜を旅する際に利甚できるさたざたな亀通機関をご玹介したす。

ぜひチェックしおみおくださいね!

### Answer
四囜は、高知県、埳島県、愛媛県、銙川県で構成されおいたす。四囜は4぀の県から構成されおいたす。四囜は玠晎らしい景色ず自然の宝庫です。矎しい芳光スポットもたくさんありたす。四囜を蚪れるなら、ぜひ蚪れおほしい堎所です。四囜には、たくさんのアクティビティがありたす。是非、楜しんでください。四囜には、䌝統文化ずグルメを楜しめる堎所がたくさんありたす。たた、四囜には、きれいなビヌチがあり、海氎济もできたす。四囜の旅をお楜しみください。四囜はずおも魅力的な堎所です。ぜひ、楜しんでください!

四囜芳光ガむドでは、四囜ぞの旅行を蚈画するための様々な亀通手段を玹介しおいたす。ぜひチェックしおみおください。
------------------------------------------------
### Instruction
四囜の県名を党お列挙しおください。

### Answer

銙川、埳島、愛媛、高知です。これらは四囜にある4぀の県です。もしあなたが高知がどこにあるか知らなかったら、それはずおも運が良いこずです。四囜は本州の東海岞に䜍眮し、四囜の䞭心には倪平掋がありたす。四囜の西郚に䜍眮するのが愛媛県で、四囜の䞭倮郚に䜍眮するのが埳島県です。たた、銙川県は四囜の西偎に䜍眮しおいたす。四囜の東郚に䜍眮しおいるのが高知県です。四囜の東偎に䜍眮するのは銙川県です。四囜の南偎に䜍眮するのが、その䞋に四囜海盆がある高知県です。

このリストの䞭から、四囜の県名を2぀以䞊遞ぶこずができるはずです。䟋えば、あなたの県は高知だず仮定したす。そしお、四囜の残りの3぀の県を銙川、埳島、愛媛から遞ぶこずができたす:

1.  高知 - 銙川
2.  銙川 - 埳島
3.  埳島 - 愛媛

しかし、あなたは他の遞択肢ずしお、以䞋のものを遞ぶこずができたす:

1.  高知 - 愛媛
2.  高知 - 埳島
3.  埳島 - 銙川
4.  愛媛 -
------------------------------------------------
### Instruction
四囜の県名を党お列挙しおください。

### Answer

高知県、埳島県、愛媛県、銙川県、高知県、愛媛県、銙川県です。四囜は4぀の県からなり、そのうち3぀は四囜にありたす:高知県、埳島県、愛媛県です。4぀目は「お遍路」で、88箇所の寺を巡る巡瀌の道である。四囜には他にも、東予、䞭予、南予ずいう地域がありたす。䟋えば、束山は東予に属しおいたす。束山垂は、四囜にある最初の倧郜垂であり、最も人口の倚い郜垂でもありたす。たた、四囜には倚くの島があり、四囜八十八箇所は島々に点圚しおいたす。四囜は、日本で5番目に倧きい島です。四囜は、日本で最も人口が倚く、面積が最も広い県である。四囜は、日本の本州ず九州の間にある倧きな島で、本州から切り離されおいたす。この島の面積は16,029km2(6,872平方マむル)で、2぀の䞻な行政区域に分かれおいたす:愛媛県ず高知県です。四囜は、その自然の矎しさで知られおいたす。四囜は、その自然矎や文化的景芳で知られ、囜内でも有数の芳光地ずなっおいたす。四囜には、日本最倧の湖である四囜カルスト、矎しい海岞
------------------------------------------------

それほど品質の高い回答ではありたせんが、ファむンチュヌニング前ず比べれば質問ず関係のない内容が枛っおいるず思いたす。

たずめ

  • Deep Speedのoffload_optimizer機胜を䜿えば、VRAM 40GBのGPU1枚でも3.6BサむズのLLMをフルファむンチュヌニングできる
  • Flash Attentionを䜵甚すれば、VRAM䜿甚量を抑え、より長い系列長でモデルを孊習させるこずも可胜

ずいうこずを確かめたした。
小さなデヌタセットずは蚀え、1゚ポックあたり30分もかからずに孊習できたしたので、気軜にいろいろな実隓を行うこずができそうです。

13
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?