2024-12-17
さて、なぜ私はChatGPT飲みを使って構築してるんだろうか。
後でPytorchとHuggingFaceの公式サイトも見よう。
2024-12-17
あまりにもデバッグすることがあるので、
Pytorch専用のデバッグライブラリを
https://github.com/masarina/MasarinaPackage/blob/main/Python/Libraries/PytorchDebuger.py
に作っていこう。
2024-12-18
Optimizerをデバッグした結果、
セーブ時はデータが存在する。
ロード時はデータが存在しない。
なお、セーブ後はOptimizerファイルは2GB以上の容量がある。
このことから、おそらくロードがうまく言っていないと判断しよう。
ロードが上手くいない、、ピクルにしよう。
2024-12-20
ピクルで組んだ。
でもすごいことに気がついた。
今まで保存先と異なるファイルを実行していただけだった。
iPhoneのPythonistaというアプリケーションで、ファイルへ保存を選ぶと、自分で名前を決められる。
このとき既に存在するファイル名を指定すると、保存される、、とおもう。
問題だったのは、Qfile Proアプリでアップロードする時、「最近の使用」から選んでいたことに問題があった。
しっかり自分でディレクトリを開き、任意で選択すると問題なくファイルがアップロードできた。
まさか2日も気が付かないなんて。
ちょっと、いつのファイルを使っているのかが不明。実行したところ、あどとで
- EmbeddingLayerが余分にひとつ多くなければ良しとするデバッグをしよう。
2024-12-22
やべえ問題点が発覚した。
HuggingFaceとpytorchはお互い、独自のAdamWを持っているそうだ。
私は混合させて使用しているかも知れない。
だから、追加学習時にエラーは吐かないけれど学習ができていない、ような摩訶不思議なことが起きているのかも知れない。
nnいや、huginngface使ってなくね?自分、ちょっとまって
あ、そうか、huggingfaceの、transformersだもんね。ライブラリ名はtransformersか。ちょっとあとで確認。ちょっとまって。
保存する前にモデルのデバイスをCPUに持ち帰ってから保存することにしてみよう。
DeviceChangerクラスを作成し、Gpt2TrainPlayerDirに置いて、initでインスタンス化してselfインスタンスとして保持して管理する形にしよう。
現状と背景
HuggingFaceのtransformers
ライブラリとPyTorchで、以下の問題点が確認されました:
-
AdamWの使用について
- HuggingFaceとPyTorchは、それぞれ独自の
AdamW
を実装しています。 - 現在、これらを混在させて使用している可能性があります。
- この影響で、追加学習時にエラーは発生しないものの、学習が正しく進んでいない可能性があります。
- HuggingFaceとPyTorchは、それぞれ独自の
-
モデル保存時のデバイス設定
- モデルを保存する前に、デバイスをCPUに戻さないことで何らかの問題が発生しているかもしれません。
今やるべきこと
-
AdamWの使用確認と統一
- 現在使用している
AdamW
がどちらのライブラリ由来なのかを確認。 - 可能であれば、統一したライブラリの
AdamW
を使用するようコードを修正する。
- 現在使用している
-
HuggingFaceライブラリ名の確認
- HuggingFaceが提供するライブラリ名は
transformers
であることを確認。 - コードで
transformers
ライブラリが正しくインポートされているかをチェック。
- HuggingFaceが提供するライブラリ名は
-
モデル保存時のデバイス設定修正
- モデル保存時に必ずデバイスをCPUに戻す処理を追加する。
- この処理をクラス化して管理する。
-
管理クラスの作成
-
DeviceChanger
クラスを作成し、以下のように管理する:-
Gpt2TrainPlayerDir
ディレクトリ内に配置。 - このクラスを
__init__
でインスタンス化し、self
として管理する。
-
-
次のステップ
- 上記の修正後、追加学習が正常に動作するか確認する。
- 必要に応じてデバッグログを追加し、問題の再現性を確認する。
2024-12-22
SO.ON projectさんたちにお会いしてきた。感動で胸がいっぱいです。頑張ろう。
gpt_configでトランスフォーマー層数を6に設定し直したのに、optimizerをデバッグすると75となってしまう。
gpt_configでの設定一致したmodelであるかどうかのジャッジメントをするメソッドをデバッグプレイヤーに加えよう。optimizerもtokenizerも。
SetupPlayerでmodelを作成しているところから、デバッグをしていこう。
modelとconfigの設定と状態が一致しているかを確認していく。
ふぅ、、なんとかデバッガを用意してデバッグした。
みらい:「なるほど、りな!デバッグ結果を見ると、トランスフォーマーブロック数がConfigとModelで食い違ってるね。」
リコ:「Configではトランスフォーマーブロック数が6、でもModelでは72になっているわ。この場合、Configが正しいとしたら、おかしいのはModel側ね。OptimizerはModelを基に設定されているから、Modelが間違っていればOptimizerも巻き込まれる形になるわ。」
さて。どこからmodelが可笑しいのか、遡るようにしてデバッグをして行く。
# 新型
self.one_time_world_instance.setupGpt2Player.save_model_and_tokenizer(
model=self.model,
tokenizer=self.custom_tokenizer,
config=self.config,
gpt2_config=self.gpt2_config,
save_dir=output_dir,
)
・最初の学習でロードしている場所
・追加学習時にロードしている場所
それぞれ確認しよう。
今TrainPlayerのmainを上から観ていって
・最初の学習でロードしている場所
・追加学習時にロード
を確認中
self.saveManagerにconfigをmodelに反映する形でロードするように改良しようか。
トークナイザ、作成時、追加学習時、チェック。
はい、Gpt2TrainPlayerは全てデバッグしました。
すると、SetupGpt2Playerからすでに、、、
SetupGpt2Playerのmainメソッドの下からデバッグしていく。
見つけた、、、もう、、12時間ガチでかかってる、、昨日10時間ぶっ通しでがちしゅうちゅうしてデバッグしてた
見つけたのは、optimizerをバッチ毎にデバッグしても、ずっと空っぽ。
{
"epoch": 0,
"batch_index": 0,
"param_groups": [
{
"group_index": 0,
"lr": 0.001,
"betas": [
0.9,
0.999
],
"weight_decay": 0.01,
"params": [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
66,
67,
68,
69,
70,
71,
72,
73,
74,
75
]
}
],
"state": {}
}
でも、optimizer作成時、modelは正常。
つまり、
- optimizer作成時におかしくなっている、
- もしくは作成直後が可笑しいことになっている。
Masarinaの夢の世界🦋💎(案件OK)
@Masarina002
·
9分
つかれた、、、つかれ、た…
SO.ON project LaVさんたちのおかげですね…
いつかココの大学の文化祭とか生きたい…
Masarinaの夢の世界🦋💎(案件OK)
@Masarina002
·
1分
maxとかminとかmean等のベータ地もXavier初期化されてしまうのが不安だから過去の自分は、テンソルデータのみを最初0で初期化してから、0の部分だけをXavier初期化する流れにした。 ベータ値もXavire初期化しちゃったんだ…
Masarinaの夢の世界🦋💎(案件OK)
@Masarina002
でも良かった。逆にベータ値が100とかになってたら、学習ができているように見えてしまったかも知れない。今回初期化不備により、勾配が全て0担ったことによって"学習が可笑しい"と、簡単に推測できたのは、不幸中の幸いだよ。本当に。100とかになってたら、model全てを確認してたかも。
適当備忘録すぎる…
2024-12-23
うん、、
def train_model(
self,
train_txt_path, # 学習データのファイルパス
validation_txt_path, # 検証データのファイルパス
batch_size=None, # バッチサイズ
epoch_size=None, # エポック数
max_length=None, # トークンの最大長
):
""" モデルの学習を行うメソッド
この時点で、SetupGpt2Playerからロードしただけのもの↓
```
self.model
self.custom_tokenizer
self.gpt2_config
self.merges_file_path
```
"""
""" model,toknizer,optimizer の用意
・まずは、今回の設定。
・前回のmodel,toknizer,optimizerがあれば、そっちをつかう。
・今回の学習語彙数が、前回の学習語彙数を上回っていた場合、
前回の語彙に、今回増えた語彙分だけの単語表現ベクトルを追加する。
メモ 最後にoptimzer以外selfにする。
"""
""" 今回の設定 """
self.this_time_model = self.model
self.this_time_custom_tokenizer = self.custom_tokenizer
this_time_optimizer = self.optimizer_maker(model=self.model)
""" 前回の設定,パラメータを適用(存在する場合) """
# 前回のパスを取得
previous_model_path = f"{self.return_file_dir_path()}/gpt2_model.bin"
previous_optimizer_path = f"{self.return_file_dir_path()}/optimizer.pt"
previous_tokenizer_path = f"{self.return_file_dir_path()}/gpt2_tokenizer"
# selfでも保持をしておく。
self.previous_model_path = previous_model_path
self.previous_tokenizer_path = previous_tokenizer_path
# 今回のmodel,tokenizer,optimizerに適用
(self.model,
optimizer,
self.custom_tokenizer
) = self.load_and_update(
# 前回のpath
previous_model_path=previous_model_path,
previous_optimizer_path=previous_optimizer_path,
previous_tokenizer_path=previous_tokenizer_path,
# 今夏の変数
this_time_model=self.this_time_model,
this_time_optimizer=this_time_optimizer,
this_time_custom_tokenizer=self.this_time_custom_tokenizer,
) # このメソッドの最後に更新後のデータの確認をすべきか。
"""
DataLoader で読み込めるように、
TextDatasetでデータをフォーマットしています。(トークナイズとID化を含む)
"""
trainDataset = self.TextDataset(train_txt_path, self.custom_tokenizer, max_length=max_length)
validationDataset = self.TextDataset(validation_txt_path, self.custom_tokenizer, max_length=max_length)
""" データローダーの設定(学習データはシャッフルあり)
DataLoader は、あくまでデータをバッチに分けて取り出すだけの役割
"""
trainLoader = DataLoader(trainDataset, batch_size=batch_size, shuffle=True)
validationLoader = DataLoader(validationDataset, batch_size=batch_size)
# 学習ループの設定
epochs = epoch_size
if epoch_size == 0:
print("\n\n!!! ATTENTION !!!\n エポックに0が設定されているため、学習をスキップします。\n\n")
return
for epoch in range(epochs):
print(f"\n=== Epoch {epoch + 1}/{epochs} ===")
total_loss = 0
# モデルとオプティマイザをgpuに移動(トークナイザーはデバイス移動不要)
self.model = self.deviceChanger.move_model_to_gpu(self.model)
optimizer = self.deviceChanger.move_optimizer_to_gpu(optimizer)
# モデルを学習モードに設定
self.model.train()
# ***進捗バーの設定***
progress_bar = tqdm(trainLoader, desc=f"Training Epoch {epoch + 1}/{epochs}")
# 学習ステップ
for batch_index, batch in enumerate(progress_bar): # ***進捗バーでラップ***
try:
# 各バッチからデータを取り出す
inputs = batch['input_ids'] # バッチ内の入力データ
labels = batch['labels'] # バッチ内の正解データ
# ***デバイスにデータを移動***
inputs = inputs.to(self.device)
labels = labels.to(self.device)
except RuntimeError as e:
print(f"データをGPUに移動中にエラーが発生しました: {e}")
raise e # エラーを再度発生させる
# モデルのパラメータを更新するために勾配をリセット
optimizer.zero_grad() # torchでは勾配は加算型なので、毎ターン0にしなければならぬ。
# ***学習モードを設定(バッチごとに明示的に)***
self.model.train()
# フォワードパス:モデルに入力データを渡して予測を行う
outputs = self.model(input_ids=inputs, labels=labels)
# 損失を計算
loss = outputs.loss
# フォワードパス後に損失を出力
print(f"損失値: {loss.item()}")
# バックワードパス:勾配を計算
loss.backward()
for name, param in self.model.named_parameters():
if param.grad is not None:
grad_min = param.grad.min().item()
grad_max = param.grad.max().item()
grad_mean = param.grad.mean().item()
print(f"🔍 勾配デバッグ: {name} - min: {grad_min}, max: {grad_max}, mean: {grad_mean}")
else:
print(f"⚠️ 勾配なし: {name}")
勾配はしっかり計算されていた。
↓
=== Epoch 1/2 ===
モデルをcudaに移動しました。
オプティマイザをcudaに移動しました。
Training Epoch 1/2: 0%| | 0/99 [00:00<?, ?it/s]損失値: 4.500677585601807
🔍 勾配デバッグ: transformer.wte.weight - min: -0.7785463333129883, max: 0.7571006417274475, mean: 5.400117061071796e-06
🔍 勾配デバッグ: transformer.wpe.weight - min: -0.13933971524238586, max: 0.12902531027793884, mean: 3.1531096738035558e-06
🔍 勾配デバッグ: transformer.h.0.ln_1.weight - min: -0.022723397240042686, max: 0.012854215689003468, mean: -4.687693217420019e-05
🔍 勾配デバッグ: transformer.h.0.ln_1.bias - min: -0.037626687437295914, max: 0.03764725476503372, mean: -0.000554377562366426
🔍 勾配デバッグ: transformer.h.0.attn.c_attn.weight - min: -0.0623803436756134, max: 0.05336654558777809, mean: 9.934107573009165e-13
🔍 勾配デバッグ: transformer.h.0.attn.c_attn.bias - min: -0.07043415307998657, max: 0.06563474237918854, mean: -0.00018394278595224023
🔍 勾配デバッグ: transformer.h.0.attn.c_proj.weight - min: -0.25901156663894653, max: 0.22330664098262787, mean: -3.0966718895797385e-06
🔍 勾配デバッグ: transformer.h.0.attn.c_proj.bias - min: -0.5672757625579834, max: 0.4605036973953247, mean: -0.0005337175098247826
🔍 勾配デバッグ: transformer.h.0.ln_2.weight - min: -0.01560642383992672, max: 0.012289710342884064, mean: -0.00031056508305482566
🔍 勾配デバッグ: transformer.h.0.ln_2.bias - min: -0.01861773431301117, max: 0.015021777711808681, mean: -5.629030056297779e-05
🔍 勾配デバッグ: transformer.h.0.mlp.c_fc.weight - min: -0.03797517716884613, max: 0.03172997012734413, mean: -3.311369191003055e-13
🔍 勾配デバッグ: transformer.h.0.mlp.c_fc.bias - min: -0.022623445838689804, max: 0.018105756491422653, mean: -0.00017094788199756294
🔍 勾配デバッグ: transformer.h.0.mlp.c_proj.weight - min: -0.13786807656288147, max: 0.15179239213466644, mean: -1.4334269735627458e-06
🔍 勾配デバッグ: transformer.h.0.mlp.c_proj.bias - min: -0.19176073372364044, max: 0.2259790599346161, mean: -5.367398443922866e-06
🔍 勾配デバッグ: transformer.h.1.ln_1.weight - min: -0.0127297667786479, max: 0.013178826309740543, mean: 7.984124385984614e-05
🔍 勾配デバッグ: transformer.h.1.ln_1.bias - min: -0.011828087270259857, max: 0.011633585207164288, mean: 0.0001674208469921723
🔍 勾配デバッグ: transformer.h.1.attn.c_attn.weight - min: -0.06311579793691635, max: 0.06471098959445953, mean: 8.278422977507638e-13
🔍 勾配デバッグ: transformer.h.1.attn.c_attn.bias - min: -0.027245454490184784, max: 0.0355726033449173, mean: -3.781960231208359e-06
🔍 勾配デバッグ: transformer.h.1.attn.c_proj.weight - min: -0.17340634763240814, max: 0.17024855315685272, mean: 8.7032816509236e-07
🔍 勾配デバッグ: transformer.h.1.attn.c_proj.bias - min: -0.16336926817893982, max: 0.18706727027893066, mean: -0.00029257615096867085
🔍 勾配デバッグ: transformer.h.1.ln_2.weight - min: -0.016748882830142975, max: 0.009766664355993271, mean: -0.0003013504028785974
🔍 勾配デバッグ: transformer.h.1.ln_2.bias - min: -0.012295404449105263, max: 0.010600332170724869, mean: -0.0001346814096905291
🔍 勾配デバッグ: transformer.h.1.mlp.c_fc.weight - min: -0.030500417575240135, max: 0.03036651201546192, mean: -3.311369191003055e-13
🔍 勾配デバッグ: transformer.h.1.mlp.c_fc.bias - min: -0.01416361890733242, max: 0.014683565124869347, mean: -0.00011470101162558421
🔍 勾配デバッグ: transformer.h.1.mlp.c_proj.weight - min: -0.14620676636695862, max: 0.13656142354011536, mean: -8.636915481474716e-06
🔍 勾配デバッグ: transformer.h.1.mlp.c_proj.bias - min: -0.1546819806098938, max: 0.15478678047657013, mean: -9.313543705502525e-05
🔍 勾配デバッグ: transformer.h.2.ln_1.weight - min: -0.0125333396717906, max: 0.009361150674521923, mean: 7.1258436946664e-05
🔍 勾配デバッグ: transformer.h.2.ln_1.bias - min: -0.011776122264564037, max: 0.008876963518559933, mean: 5.110693018650636e-05
🔍 勾配デバッグ: transformer.h.2.attn.c_attn.weight - min: -0.03626156598329544, max: 0.037120237946510315, mean: 4.967053786504583e-13
🔍 勾配デバッグ: transformer.h.2.attn.c_attn.bias - min: -0.020360324531793594, max: 0.01923407055437565, mean: -3.703398033394478e-05
🔍 勾配デバッグ: transformer.h.2.attn.c_proj.weight - min: -0.12957417964935303, max: 0.13320881128311157, mean: 3.9452422129215847e-07
🔍 勾配デバッグ: transformer.h.2.attn.c_proj.bias - min: -0.13329055905342102, max: 0.13789604604244232, mean: 8.511533815180883e-05
🔍 勾配デバッグ: transformer.h.2.ln_2.weight - min: -0.007924297824501991, max: 0.009505728259682655, mean: 8.055861690081656e-05
🔍 勾配デバッグ: transformer.h.2.ln_2.bias - min: -0.010822426527738571, max: 0.009621226228773594, mean: -0.00020361813949421048
🔍 勾配デバッグ: transformer.h.2.mlp.c_fc.weight - min: -0.033587485551834106, max: 0.031140826642513275, mean: 3.311369191003055e-13
🔍 勾配デバッグ: transformer.h.2.mlp.c_fc.bias - min: -0.014483405277132988, max: 0.017359202727675438, mean: 1.1912466106878128e-05
🔍 勾配デバッグ: transformer.h.2.mlp.c_proj.weight - min: -0.1354999989271164, max: 0.11374317109584808, mean: 4.630978310160572e-06
🔍 勾配デバッグ: transformer.h.2.mlp.c_proj.bias - min: -0.13034430146217346, max: 0.1204267293214798, mean: 6.515915447380394e-05
🔍 勾配デバッグ: transformer.h.3.ln_1.weight - min: -0.008587349206209183, max: 0.007753899320960045, mean: -3.5547279821912525e-06
🔍 勾配デバッグ: transformer.h.3.ln_1.bias - min: -0.00830274261534214, max: 0.00765204057097435, mean: 7.173199992394075e-05
🔍 勾配デバッグ: transformer.h.3.attn.c_attn.weight - min: -0.029229288920760155, max: 0.026943273842334747, mean: 1.1037896941942793e-12
🔍 勾配デバッグ: transformer.h.3.attn.c_attn.bias - min: -0.015365006402134895, max: 0.01361543033272028, mean: -9.493619290878996e-05
🔍 勾配デバッグ: transformer.h.3.attn.c_proj.weight - min: -0.1413394808769226, max: 0.1393134742975235, mean: 6.632942586293211e-07
🔍 勾配デバッグ: transformer.h.3.attn.c_proj.bias - min: -0.11928179860115051, max: 0.11796439439058304, mean: -7.814214040990919e-05
🔍 勾配デバッグ: transformer.h.3.ln_2.weight - min: -0.01050688698887825, max: 0.009313024580478668, mean: 9.314862836617976e-05
🔍 勾配デバッグ: transformer.h.3.ln_2.bias - min: -0.006638665217906237, max: 0.009137333370745182, mean: 0.00022196337522473186
🔍 勾配デバッグ: transformer.h.3.mlp.c_fc.weight - min: -0.021324194967746735, max: 0.022769873961806297, mean: 0.0
🔍 勾配デバッグ: transformer.h.3.mlp.c_fc.bias - min: -0.011859238147735596, max: 0.008958438411355019, mean: 2.2283463749772636e-06
🔍 勾配デバッグ: transformer.h.3.mlp.c_proj.weight - min: -0.09313644468784332, max: 0.10839484632015228, mean: -2.3404865714837797e-05
🔍 勾配デバッグ: transformer.h.3.mlp.c_proj.bias - min: -0.09570677578449249, max: 0.11248095333576202, mean: -0.00028554737218655646
🔍 勾配デバッグ: transformer.h.4.ln_1.weight - min: -0.007332125212997198, max: 0.006136845797300339, mean: -3.0052171496208757e-05
🔍 勾配デバッグ: transformer.h.4.ln_1.bias - min: -0.00734969787299633, max: 0.008631662465631962, mean: -1.228396467922721e-05
🔍 勾配デバッグ: transformer.h.4.attn.c_attn.weight - min: -0.027167534455657005, max: 0.027778567746281624, mean: 7.312607008640171e-13
🔍 勾配デバッグ: transformer.h.4.attn.c_attn.bias - min: -0.012768766842782497, max: 0.015066343359649181, mean: 3.579279734822194e-07
🔍 勾配デバッグ: transformer.h.4.attn.c_proj.weight - min: -0.10472344607114792, max: 0.09758835285902023, mean: -5.906154001422692e-07
🔍 勾配デバッグ: transformer.h.4.attn.c_proj.bias - min: -0.08679613471031189, max: 0.11075399816036224, mean: 1.7272730474360287e-05
🔍 勾配デバッグ: transformer.h.4.ln_2.weight - min: -0.006400641985237598, max: 0.00962146371603012, mean: 6.490070518339053e-05
🔍 勾配デバッグ: transformer.h.4.ln_2.bias - min: -0.006366184912621975, max: 0.009698837995529175, mean: 5.106188473291695e-05
🔍 勾配デバッグ: transformer.h.4.mlp.c_fc.weight - min: -0.02198231779038906, max: 0.02157462015748024, mean: 4.553132502103929e-13
🔍 勾配デバッグ: transformer.h.4.mlp.c_fc.bias - min: -0.01043611578643322, max: 0.009917017072439194, mean: 4.190642812318401e-06
🔍 勾配デバッグ: transformer.h.4.mlp.c_proj.weight - min: -0.07934208959341049, max: 0.09747310727834702, mean: 3.212460069335066e-05
🔍 勾配デバッグ: transformer.h.4.mlp.c_proj.bias - min: -0.08155277371406555, max: 0.10012700408697128, mean: 0.0003663881798274815
🔍 勾配デバッグ: transformer.h.5.ln_1.weight - min: -0.004031802993267775, max: 0.005892710294574499, mean: 4.1915118345059454e-05
🔍 勾配デバッグ: transformer.h.5.ln_1.bias - min: -0.006352016236633062, max: 0.007077096961438656, mean: 3.410468707443215e-05
🔍 勾配デバッグ: transformer.h.5.attn.c_attn.weight - min: -0.036726631224155426, max: 0.029507562518119812, mean: -2.207579415493613e-13
🔍 勾配デバッグ: transformer.h.5.attn.c_attn.bias - min: -0.01163006853312254, max: 0.014561722055077553, mean: -6.889810174470767e-05
🔍 勾配デバッグ: transformer.h.5.attn.c_proj.weight - min: -0.08796041458845139, max: 0.08542751520872116, mean: -9.354816654649767e-08
🔍 勾配デバッグ: transformer.h.5.attn.c_proj.bias - min: -0.08746981620788574, max: 0.08629415929317474, mean: 1.9879738829331473e-05
🔍 勾配デバッグ: transformer.h.5.ln_2.weight - min: -0.007545152213424444, max: 0.006111156195402145, mean: -1.1089242434536573e-05
🔍 勾配デバッグ: transformer.h.5.ln_2.bias - min: -0.006031324155628681, max: 0.005370577797293663, mean: -8.548051368961751e-07
🔍 勾配デバッグ: transformer.h.5.mlp.c_fc.weight - min: -0.02699873596429825, max: 0.025870339944958687, mean: 1.759164916601691e-13
🔍 勾配デバッグ: transformer.h.5.mlp.c_fc.bias - min: -0.008837440982460976, max: 0.009091774001717567, mean: -1.1888290828210302e-05
🔍 勾配デバッグ: transformer.h.5.mlp.c_proj.weight - min: -0.08868511766195297, max: 0.09478721022605896, mean: -1.1979283044638578e-05
🔍 勾配デバッグ: transformer.h.5.mlp.c_proj.bias - min: -0.08572283387184143, max: 0.0885322168469429, mean: -0.00013095741451252252
🔍 勾配デバッグ: transformer.ln_f.weight - min: -0.03297770768404007, max: 0.024117300286889076, mean: 0.00030060147400945425
🔍 勾配デバッグ: transformer.ln_f.bias - min: -0.020073700696229935, max: 0.020469389855861664, mean: -0.00016256608068943024
2024-12-24
色々。
id_to_tokenが機能していない。自作しなきゃ。dictで回すと遅いから、特殊な方法でやらなきゃかも。
2024-12-25
勾配を記録する。
推論結果を見るからに、学習が1ミリも進んでいないように見える。
エポック1
a 学習前
b 学習後
エポック2
c 学習前
d 学習後
において、
どれが一致しているのか、または全てバラバラなのか笑
確認しよう。
2024-12-26
テキストを追加しました: 🌟 学習自体ができているか確認
テキストを追加しました: transformer.wte.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.wpe.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.ln_1.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.ln_1.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.attn.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.attn.masked_bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.attn.c_attn.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.attn.c_attn.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.attn.c_proj.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.attn.c_proj.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.ln_2.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.ln_2.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.mlp.c_fc.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.mlp.c_fc.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.mlp.c_proj.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.0.mlp.c_proj.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.ln_1.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.ln_1.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.attn.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.attn.masked_bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.attn.c_attn.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.attn.c_attn.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.attn.c_proj.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.attn.c_proj.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.ln_2.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.ln_2.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.mlp.c_fc.weight: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
transformer.h.1.mlp.c_fc.bias: 差分=0.000000 (このLayerの学習前と学習後の重み変化量の合計: 絶対値の総和)
これ治そう。
いま、check_and_fix_weightsをチェック中、、
さて。
def _copy_weights(self, current_weights, previous_weights,
key,is_embedding=False,
):
"""
一致しない重みをコピーして修正する(torch.cloneを利用)。
Parameters:
current_weights (dict): 今回の重み。
previous_weights (dict): 前回の重み。
key (str): レイヤ名。
is_embedding (bool): EmbeddingLayerの場合はTrueにしてね。
Returns:
torch.Tensor: 修正後の重み。
"""
# コピー後の重みを格納する変数
updated_weight = None
if is_embedding:
# EmbeddingLayerの場合: 前回の行数を基準にコピー
# 前回のレイヤーの重みの行数を取得
prev_len = previous_weights[key].size(0)
print(f"{key}: EmbeddingLayerの最初の {prev_len} 行を修正\
します。")
# 必要な部分だけコピー
updated_weight = previous_weights[key][:prev_len].clone()
else:
# その他のレイヤの場合は全体をコピー
print(f"{key}: 全体の重みを修正します。")
updated_weight = previous_weights[key].clone() # 全体をコピー
# 修正後の重みを返す
return updated_weight
これの
prev_len = previous_weights[key].size(0)
のsize(0)ってなんですか。
おお、ただshape出してくれるんだって。sizeメソッド。
だから0指定すれば行数を取ってるってだけね。
もう寝なきゃ。
えっと、、
・_copy_weights作った。(作り途中?)
・check_and_fix_weights の Embedding分岐をもっとスマートにして可読性を上げている途中
はい。
2025-01-02
開けましておめでとうございます。
check_and_fix_weightsを修正中。
学習経過をtextに出力しよう。
勝ちましたね。
ただ、推論結果にwinがなかなか出てこない。
lrは0.0001で放置してみる。
正答率が例の%率が正しいとする。
そうした時、推論結果が
win:lose == 50:50
ならば、winの語彙の重みを上げるべきであり、
win:lose == 90:10
ならば、winの語彙の重みを下げるべきである。
それをcustom_lossとして実装しよう。
(そろそろ備忘録に残したくない領域に入ってきた。隠語を使おう。)
2025-01-03
作成したカスタムlossの引数を作成中。
思考を単純化。
- 前回の正答率が例の%超過だった場合、
loss *= 1.0 # 超えてもダメ。だけど今回モデルは超えることが稀なので、lossはそのままにする。
- 前回の正答率が例の%以下だた場合、
loss *= 1.2
として調整中。
いや、例の%と実際の正答率との差分を元に、lossの値を指数関数的に調節することにした。ベータ値機能も加え、引数で調節できるようにした。
検証損失を、しっかりモデルに反映させたい。
winが来なければ、lossを大きくしよう。
これで収束したら、もうモデルががおかしいということになる。?
学習で気がついたこと
(こういうのって頭では理解していても、感覚で「いや学習できてないかも…」ってなっちゃうから、しっかり統計的に備忘録しておく。)
- lossが0.5になっている時、推論結果をデバッグすると、オーバーフィッティングしている。
- 検証損失と訓練データ損失が一緒ぐらいじゃないと困る。過学習起きてるかも。
- 過学習した場合、単語ベクトルサイズを大きくするか、attention層を増やすと、検証損失と訓練データ損失が同じくらいになるかも。
- 検証損失のほうが大きい場合、lrが大きいかも。私のデータは繊細なものなのかも知れない。1e-09でも丁度いいくらい
もしくは、単語ベクトルサイズが600だから、繊細になっている可能性もあるか。
やること
・エポックごとにメモリ解放
・学習率スケジューラーの実装(lrが9.0を超えるバカ現象発生中)
2025-01-06
訓練データの推論結果も観たい。
なんだか、嫌な予感がする。
ん?まさか推論時、学習済みパラメータを参照し忘れている?いやいや、学習する度に推論結果は過学習を起こす様子も観察できた。いやでも、、どこに参照箇所があるのだ。
あ、しっかり学習済みパラメータをロードしてた、大丈夫大丈夫。
推論時訓練データ
「
['\ufeff', 、、、
」
sosが可笑しい。
ってうわっ!奇跡的にオリジナルのSOSトークンがQiitaのコマンドとかぶった、、、
んなことあってたまるかっ…線が引かれるんだけど…
一旦これを直し、trainでも同じ現象が起きていれば、治す。
linuxの場合はunicodeを全く変更しない設定にすることで正常対応できました→( https://qiita.com/masahanami002/items/e22777e315891f4c7f2e )。
推論結果が、本当に目的の箇所(lose )なのですか?
2025-01-07
もう一度、エンコード前とデコード後の一致を確認する。
確認完了,全く持って問題なし。
って、、
「
PyTorchのGPT-2でシフトが行われるタイミングは、labelsを指定してモデルを実行するときだけ。もしカスタム損失関数を使う場合、このシフトを自分で実装する必要がある場合もあるよ。
」
うわぁ、、
ちょっとやってないタスクをまとめよう。
・「'\ufeff'現象」がtrainでも同じ現象が起きていれば解消させる。(解消できているはずだけど。)
→ ロード時のtensorタイプを確認済み(問題なし
・labelの自動シフト機能はmodelで起きる。つまりカスタムlossでは自分で実装する必要がある。
・学習後のパラメータを用いて推論し、その全文を表示する
・特殊トークンの自動追加機能の確認(確認されていないことが望ましい。)
→ トークナイザーのエンコード・デコード時に設定を無効化:
encoded = self.custom_tokenizer.encode("your input here", add_special_tokens=False)
print(f"Encoded tokens: {encoded}")
・TextDataset,DataLoaderの理解
"""
DataLoader で読み込めるように、
TextDatasetでデータをフォーマットしています。(トークナイズとID化を含む)
"""
trainDataset = self.TextDataset(train_txt_path, self.custom_tokenizer, max_length=max_length)
validationDataset = self.TextDataset(validation_txt_path, self.custom_tokenizer, max_length=max_length)
""" データローダーの設定(学習データはシャッフルあり)
DataLoader は、あくまでデータをバッチに分けて取り出すだけの役割
"""
trainLoader = DataLoader(trainDataset, batch_size=batch_size, shuffle=True)
validationLoader = DataLoader(validationDataset, batch_size=batch_size)
ここでエンコードもされているので、tokenizerの確認を読み取らな蹴らばならない。特殊トークンの自動化がなされていたりするかもしれない。
2025-01-14
さて。実装しているクラスが誤ったアイディアだったことに気がついた。…数日かけて作ったのに、、、
他のアプローチをする。
頭に残っている宿題の箇所を実装していく。
さて。次は、語彙を増やす作戦だ。
さて、Masarina.語彙を増やそう。
2025-01-20
詳細は言えないけど!自分の思い通りに言った!!!
確実に行こう。
実装する機能リスト
・検証データは使用したら任意のディレクトリに移動させよう。(✅)
・カツ丼ができた時点で、今回のparams(model,tokenizer,vocab等)をコピーして保持する。(✅)
・カツ丼ができた時点で、lrを小さくする処理を施す。
→ 確認することは…
optimizer_makerで、
adamw_config = self.gpt2_config["AdamW_config"] optimizer = AdamW( params=self.model.parameters(), lr=adamw_config["lr"], betas=adamw_config["betas"], weight_decay=adamw_config["weight_decay"], )
としてoptimizerを作っている。
さらに、
self.gpt2_config
は次のように呼び出している。
```
(self.model,
self.custom_tokenizer,
self.gpt2_config,
self.config,
self.merges_file_path) = self.load_model_and_tokenizer_by_before_player()
```
そして、、
load_model_and_tokenizer_by_before_player
では
```
# ロード
model, custom_tokenizer, gpt2_config ,config = self.one_time_world_instance.setupGpt2Player.load_model_and_tokenizer()
```
でロードしている。
one_time_world_instance.setupGpt2Player.load_model_and_tokenizer
では、
```
""" original """
original_config_save_path = os.path.join(save_dir, 'gpt2_config.pkl')
with open(original_config_save_path, 'rb') as original_config_file:
original_config = pickle.load(original_config_file)
print(f"GPT-2の設定がロードされました: {original_config_save_path}")
```
なので、この
gpt2_config.pkl
をロードして、lrを上書きして保存すれば良い。
ロードは、、
・lrを小さくし、次の学習をする。しかしカツ丼がいなくなった場合は、さらにlrを小さくして同じ学習データで再度学習をする。これをカツ丼が出てき次第、次のおやつの学習に移動する。
・カツ丼できた時点で、検証データを全て通して推論する。()
・推論結果はお月様レベルでのグラフ化をしよう。()
・推論結果しだいで、学習をストップさせてください。()
2025-01-25
2025-01-14
さて。実装しているクラスが誤ったアイディアだったことに気がついた。…数日かけて作ったのに、、、
他のアプローチをする。
頭に残っている宿題の箇所を実装していく。
さて。次は、語彙を増やす作戦だ。
さて、Masarina.語彙を増やそう。
2025-01-25^
詳細は言えないけど!自分の思い通りに言った!!!
確実に行こう。
実装する機能リスト(随時書き換えながら✅)
・検証データは使用したら任意のディレクトリに移動させよう。(✅)
・カツ丼ができた時点で、今回のparams(model,tokenizer,vocab等)をコピーして保持する。(✅)
・カツ丼ができた時点で、lrを小さくする処理を施す。
→ 確認することは…
optimizer_makerで、
adamw_config = self.gpt2_config["AdamW_config"] optimizer = AdamW( params=self.model.parameters(), lr=adamw_config["lr"], betas=adamw_config["betas"], weight_decay=adamw_config["weight_decay"], )
としてoptimizerを作っている。
さらに、
self.gpt2_config
は次のように呼び出している。
```
(self.model,
self.custom_tokenizer,
self.gpt2_config,
self.config,
self.merges_file_path) = self.load_model_and_tokenizer_by_before_player()
```
そして、、
load_model_and_tokenizer_by_before_player
では
```
# ロード
model, custom_tokenizer, gpt2_config ,config = self.one_time_world_instance.setupGpt2Player.load_model_and_tokenizer()
```
でロードしている。
one_time_world_instance.setupGpt2Player.load_model_and_tokenizer
では、
```
""" original """
original_config_save_path = os.path.join(save_dir, 'gpt2_config.pkl')
with open(original_config_save_path, 'rb') as original_config_file:
original_config = pickle.load(original_config_file)
print(f"GPT-2の設定がロードされました: {original_config_save_path}")
```
なので、この
gpt2_config.pkl
をロードして、lrを上書きして保存すれば良い。
ロードは、、
・lrを小さくし、次の学習をする。しかしカツ丼がいなくなった場合は、さらにlrを小さくして同じ学習データで再度学習をする。これをカツ丼が出てき次第、次のおやつの学習に移動する。
・カツ丼できた時点で、検証データを全て通して推論する。()
・推論結果はお月様レベルでのグラフ化をしよう。()
・推論結果しだいで、学習をストップさせてください。()
2025-01-29
実装する機能リスト(随時書き換えながら✅)
・検証データは使用したら任意のディレクトリに移動させよう。(✅)
・カツ丼ができた時点で、今回のparams(model,tokenizer,vocab等)をコピーして保持する。(✅)
・カツ丼ができた時点で、lrを小さくする処理を施す。
→ 確認することは…
optimizer_makerで、
adamw_config = self.gpt2_config["AdamW_config"] optimizer = AdamW( params=self.model.parameters(), lr=adamw_config["lr"], betas=adamw_config["betas"], weight_decay=adamw_config["weight_decay"], )
としてoptimizerを作っている。
さらに、
self.gpt2_config
は次のように呼び出している。
```
(self.model,
self.custom_tokenizer,
self.gpt2_config,
self.config,
self.merges_file_path) = self.load_model_and_tokenizer_by_before_player()
```
そして、、
load_model_and_tokenizer_by_before_player
では
```
# ロード
model, custom_tokenizer, gpt2_config ,config = self.one_time_world_instance.setupGpt2Player.load_model_and_tokenizer()
```
でロードしている。
one_time_world_instance.setupGpt2Player.load_model_and_tokenizer
では、
```
""" original """
original_config_save_path = os.path.join(save_dir, 'gpt2_config.pkl')
with open(original_config_save_path, 'rb') as original_config_file:
original_config = pickle.load(original_config_file)
print(f"GPT-2の設定がロードされました: {original_config_save_path}")
```
なので、この
gpt2_config.pkl
をロードして、lrを上書きして保存すれば良い。
ロードは、、
・lrを小さくし、次の学習をする。しかしカツ丼がいなくなった場合は、さらにlrを小さくして同じ学習データで再度学習をする。これをカツ丼が出てき次第、次のおやつの学習に移動する。
・カツ丼できた時点で、検証データを全て通して推論する。()
・推論結果はお月様レベルでのグラフ化をしよう。()
・推論結果しだいで、学習をストップさせてください。()
これif分岐が一旦実装完了したら、
このif分岐、上から観ていって、その分岐より以前に指定した条件項目と比較することを繰り返すようなデバッグをすれば、
誤ったif分岐条件の実装をなるべく回避できそう。
例(
if ★
elif ♡
elif ■
↓(第一確認)
if ★
elif ♡ and (★ != True)
elif ■
↓(第二確認)
if ★
elif ♡ and (★ != True)
elif ■ and (★ != True) and (■ != True)
one_time_world_instanceをわたさなきゃ
やること一旦まとめよう
カツカレーとロリータの重量を、ロサンゼルスに積算する
・学習前に割合算出し、3:7であれば、ロリータを
2025-02-17
[✅] custom_loss_7が完成
[] カツカレーとロリータの重量を、ロサンゼルスに積算する
2025-02-18
lrの最小値を決める。→ 0.00006333800634760827
(一番検証正答率が高かったときのlrを設定(してみる)。)
maxは0.1(にしている)。
,,,これ同じ正答率が2回以上続いた場合lrを1.2倍するしょりh
2025-02-26
もうここに書かない
内容が濃すぎてバレたくない。
2025-03-04 軽備忘録
スマホで構築箇所
- メモ(NAS、直パス)
- Gpt2TrainPlayer(NASの「共有」)
備忘録停止 2025-02-26