Yinxing commited on
Commit
9886e67
·
1 Parent(s): 0075175

Upload 2 files

Browse files
モデルシェア&マージ(V4).ipynb ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "52e2911f-c3e0-46f0-b574-a356f5825a23",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "<bound method Module.modules of GPTNeoXForCausalLM(\n",
14
+ " (gpt_neox): GPTNeoXModel(\n",
15
+ " (embed_in): Embedding(51200, 3072)\n",
16
+ " (emb_dropout): Dropout(p=0.0, inplace=False)\n",
17
+ " (layers): ModuleList(\n",
18
+ " (0-29): 30 x GPTNeoXLayer(\n",
19
+ " (input_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
20
+ " (post_attention_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
21
+ " (post_attention_dropout): Dropout(p=0.0, inplace=False)\n",
22
+ " (post_mlp_dropout): Dropout(p=0.0, inplace=False)\n",
23
+ " (attention): GPTNeoXAttention(\n",
24
+ " (rotary_emb): GPTNeoXRotaryEmbedding()\n",
25
+ " (query_key_value): Linear(in_features=3072, out_features=9216, bias=True)\n",
26
+ " (dense): Linear(in_features=3072, out_features=3072, bias=True)\n",
27
+ " (attention_dropout): Dropout(p=0.0, inplace=False)\n",
28
+ " )\n",
29
+ " (mlp): GPTNeoXMLP(\n",
30
+ " (dense_h_to_4h): Linear(in_features=3072, out_features=12288, bias=True)\n",
31
+ " (dense_4h_to_h): Linear(in_features=12288, out_features=3072, bias=True)\n",
32
+ " (act): GELUActivation()\n",
33
+ " )\n",
34
+ " )\n",
35
+ " )\n",
36
+ " (final_layer_norm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
37
+ " )\n",
38
+ " (embed_out): Linear(in_features=3072, out_features=51200, bias=False)\n",
39
+ ")>\n"
40
+ ]
41
+ }
42
+ ],
43
+ "source": [
44
+ "# 利用するGPUを制限\n",
45
+ "import os\n",
46
+ "import torch\n",
47
+ "from peft import PeftModel, PeftConfig\n",
48
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
49
+ "os.environ[\"CUDA_VISIBLE_DEVICES\"]=\"1\" # これは0, 1, 2のGPUから、2(3番目のGPU)だけ使うという宣言。\n",
50
+ "\n",
51
+ "# メインモデル\n",
52
+ "MODEL_NAME = 'line-corporation/japanese-large-lm-3.6b'\n",
53
+ "# モデルの準備\n",
54
+ "model = AutoModelForCausalLM.from_pretrained(\n",
55
+ " MODEL_NAME,\n",
56
+ " load_in_8bit=False, # 注意:8bitで読み込むと結合不可能\n",
57
+ " device_map=\"auto\",\n",
58
+ ")\n",
59
+ "\n",
60
+ "tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=False, padding_size=\"left\", legacy=True)\n",
61
+ "tokenizer.do_lower_case = True \n",
62
+ "\n",
63
+ "print(model.modules)"
64
+ ]
65
+ },
66
+ {
67
+ "cell_type": "code",
68
+ "execution_count": 2,
69
+ "id": "0d93f697-9bf1-4214-ae31-47451edb3e7e",
70
+ "metadata": {},
71
+ "outputs": [
72
+ {
73
+ "name": "stdout",
74
+ "output_type": "stream",
75
+ "text": [
76
+ "<bound method Module.modules of PeftModelForCausalLM(\n",
77
+ " (base_model): LoraModel(\n",
78
+ " (model): GPTNeoXForCausalLM(\n",
79
+ " (gpt_neox): GPTNeoXModel(\n",
80
+ " (embed_in): Embedding(51200, 3072)\n",
81
+ " (emb_dropout): Dropout(p=0.0, inplace=False)\n",
82
+ " (layers): ModuleList(\n",
83
+ " (0-29): 30 x GPTNeoXLayer(\n",
84
+ " (input_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
85
+ " (post_attention_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
86
+ " (post_attention_dropout): Dropout(p=0.0, inplace=False)\n",
87
+ " (post_mlp_dropout): Dropout(p=0.0, inplace=False)\n",
88
+ " (attention): GPTNeoXAttention(\n",
89
+ " (rotary_emb): GPTNeoXRotaryEmbedding()\n",
90
+ " (query_key_value): Linear(\n",
91
+ " in_features=3072, out_features=9216, bias=True\n",
92
+ " (lora_dropout): ModuleDict(\n",
93
+ " (default): Dropout(p=0.05, inplace=False)\n",
94
+ " )\n",
95
+ " (lora_A): ModuleDict(\n",
96
+ " (default): Linear(in_features=3072, out_features=128, bias=False)\n",
97
+ " )\n",
98
+ " (lora_B): ModuleDict(\n",
99
+ " (default): Linear(in_features=128, out_features=9216, bias=False)\n",
100
+ " )\n",
101
+ " (lora_embedding_A): ParameterDict()\n",
102
+ " (lora_embedding_B): ParameterDict()\n",
103
+ " )\n",
104
+ " (dense): Linear(\n",
105
+ " in_features=3072, out_features=3072, bias=True\n",
106
+ " (lora_dropout): ModuleDict(\n",
107
+ " (default): Dropout(p=0.05, inplace=False)\n",
108
+ " )\n",
109
+ " (lora_A): ModuleDict(\n",
110
+ " (default): Linear(in_features=3072, out_features=128, bias=False)\n",
111
+ " )\n",
112
+ " (lora_B): ModuleDict(\n",
113
+ " (default): Linear(in_features=128, out_features=3072, bias=False)\n",
114
+ " )\n",
115
+ " (lora_embedding_A): ParameterDict()\n",
116
+ " (lora_embedding_B): ParameterDict()\n",
117
+ " )\n",
118
+ " (attention_dropout): Dropout(p=0.0, inplace=False)\n",
119
+ " )\n",
120
+ " (mlp): GPTNeoXMLP(\n",
121
+ " (dense_h_to_4h): Linear(in_features=3072, out_features=12288, bias=True)\n",
122
+ " (dense_4h_to_h): Linear(in_features=12288, out_features=3072, bias=True)\n",
123
+ " (act): GELUActivation()\n",
124
+ " )\n",
125
+ " )\n",
126
+ " )\n",
127
+ " (final_layer_norm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
128
+ " )\n",
129
+ " (embed_out): Linear(in_features=3072, out_features=51200, bias=False)\n",
130
+ " )\n",
131
+ " )\n",
132
+ ")>\n"
133
+ ]
134
+ }
135
+ ],
136
+ "source": [
137
+ "# Loraモジュールが入っているフォルダ\n",
138
+ "lora_name = \"lora-rinna-test_sample_V4\"\n",
139
+ "checkpoint = 500\n",
140
+ "\n",
141
+ "# LoRAモデルの準備\n",
142
+ "lora_model = PeftModel.from_pretrained(\n",
143
+ " model, \n",
144
+ " f'{lora_name}/checkpoint-{checkpoint}', \n",
145
+ " device_map=\"auto\"\n",
146
+ ")\n",
147
+ "\n",
148
+ "print(lora_model.modules)\n",
149
+ "\n"
150
+ ]
151
+ },
152
+ {
153
+ "cell_type": "markdown",
154
+ "id": "408c34f4-223d-4874-a610-94b41ddaa41e",
155
+ "metadata": {},
156
+ "source": [
157
+ "# 関数の読み込み"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": 4,
163
+ "id": "5eaf491b-da91-409f-87c2-7f731c569e70",
164
+ "metadata": {},
165
+ "outputs": [
166
+ {
167
+ "data": {
168
+ "text/plain": [
169
+ "['修正前:あなたは今どこにいますか? 修正後:あなたは今どこにいますか?']"
170
+ ]
171
+ },
172
+ "execution_count": 4,
173
+ "metadata": {},
174
+ "output_type": "execute_result"
175
+ }
176
+ ],
177
+ "source": [
178
+ "# プロンプト変換\n",
179
+ "def prompt_infer(original):\n",
180
+ " '''\n",
181
+ " original: 修正前の文章\n",
182
+ " revised: 修正後の文章\n",
183
+ "\n",
184
+ " ---\n",
185
+ " prompt_start: コンテクスト(前置き)\n",
186
+ " original_token: 修正前の文章ののトークン、例:修正前\n",
187
+ " revised_token: 修正後の文章のトークン、例:修正後\n",
188
+ " '''\n",
189
+ " prompt_start = '修正前の文章の誤字、脱字などを含むスペルチェックを行ってください。問題がない場合、そのままの文章を出力してください。'\n",
190
+ " #original_token = '修正前'\n",
191
+ " #revised_token = '修正後'\n",
192
+ " return f'{prompt_start}修正前:{original} 修正後:'\n",
193
+ "prompt_infer('今日はいい転居ですね!')\n",
194
+ "\n",
195
+ "\n",
196
+ "import re\n",
197
+ "# 出力表示の簡略化\n",
198
+ "def converts(texts):\n",
199
+ " return [re.findall('(修正前:.*)', text)[0]for text in texts]\n",
200
+ "\n",
201
+ "converts(['修正前の文章の誤字、脱字などを含むスペルチェックを行ってください。問題がない場合、そのままの文章を出力してください。修正前:あなたは今どこにいますか? 修正後:あなたは今どこにいますか?'])\n"
202
+ ]
203
+ },
204
+ {
205
+ "cell_type": "code",
206
+ "execution_count": 5,
207
+ "id": "f8b6b4e1-3bb7-42ff-a102-5a3434b212e0",
208
+ "metadata": {},
209
+ "outputs": [
210
+ {
211
+ "data": {
212
+ "text/plain": [
213
+ "['修正前の文章の誤字、脱字などを含むスペルチェックを行ってください。問題がない場合、そのままの文章を出力してください。修正前:空も青く、今日はほとにいい天気ですね。 修正後:',\n",
214
+ " '修正前の文章の誤字、脱字などを含むスペルチェックを行ってください。問題がない場合、そのままの文章を出力してください。修正前:いつれ、私は仙台に戻ります。 修正後:',\n",
215
+ " '修正前の文章の誤字、脱字などを含むスペルチェックを行ってください。問題がない場合、そのままの文章を出力してください。修正前:私はとっくに修士課程を終了しています。 修正後:']"
216
+ ]
217
+ },
218
+ "execution_count": 5,
219
+ "metadata": {},
220
+ "output_type": "execute_result"
221
+ }
222
+ ],
223
+ "source": [
224
+ "texts = ['空も青く、今日はほとにいい天気ですね。', 'いつれ、私は仙台に戻ります。','私はとっくに修士課程を終了しています。']\n",
225
+ "\n",
226
+ "ctexts = [prompt_infer(t) for t in texts]\n",
227
+ "ctexts"
228
+ ]
229
+ },
230
+ {
231
+ "cell_type": "code",
232
+ "execution_count": 7,
233
+ "id": "c39ba5eb-d2ad-408b-8b7f-8f7e2fa1caf5",
234
+ "metadata": {},
235
+ "outputs": [
236
+ {
237
+ "name": "stdout",
238
+ "output_type": "stream",
239
+ "text": [
240
+ "修正前:空も青く、今日はほとにいい天気ですね。 修正後:空も青く、今日はとてもよい天気ですね。\n",
241
+ "修正前:いつれ、私は仙台に戻ります。 修正後:いつれ、私は仙台に戻ります。\n",
242
+ "修正前:私はとっくに修士課程を終了しています。 修正後:私はとっくに修士課程を終了しています。\n"
243
+ ]
244
+ }
245
+ ],
246
+ "source": [
247
+ "\n",
248
+ "# 評価モード\n",
249
+ "lora_model.eval()\n",
250
+ "tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=False)\n",
251
+ "#ファインチューニングしたモデルをbest_modelと名付け、再度生成。モデル名がbest_modelに代えていることに注意。太宰的な文章が生成されている。\n",
252
+ "#best_model = trainer.model.cpu()\n",
253
+ "\n",
254
+ "for text in texts:\n",
255
+ " prompt = prompt_infer(text)\n",
256
+ " prompt_ids = tokenizer(prompt, return_tensors = 'pt',add_special_tokens=False).input_ids\n",
257
+ " outputs = lora_model.generate(\n",
258
+ " input_ids=prompt_ids.to(lora_model.device),\n",
259
+ " #prompt_ids,\n",
260
+ " do_sample=False,\n",
261
+ " max_length=60,\n",
262
+ " num_return_sequences=1,\n",
263
+ " pad_token_id=tokenizer.eos_token_id\n",
264
+ " )\n",
265
+ " #tokenizer.batch_decode(outputs, skip_special_tokens = True)\n",
266
+ " print('\\n'.join(converts(tokenizer.batch_decode(outputs, skip_special_tokens = True))))\n"
267
+ ]
268
+ },
269
+ {
270
+ "cell_type": "markdown",
271
+ "id": "e458339b-43bc-4c61-89d8-97e973c0ba3f",
272
+ "metadata": {},
273
+ "source": [
274
+ "# モデル結合\n",
275
+ "\n",
276
+ "loraパラメーターをもとのニューラルネットワークに加算し、結合する。"
277
+ ]
278
+ },
279
+ {
280
+ "cell_type": "code",
281
+ "execution_count": 8,
282
+ "id": "a7415bdf-0af0-4596-bc44-4aed4b06e9d1",
283
+ "metadata": {},
284
+ "outputs": [],
285
+ "source": [
286
+ "lora_model2 = lora_model.merge_and_unload()"
287
+ ]
288
+ },
289
+ {
290
+ "cell_type": "code",
291
+ "execution_count": 9,
292
+ "id": "5d627d97-dc39-4674-8881-be06ad0cee9a",
293
+ "metadata": {},
294
+ "outputs": [
295
+ {
296
+ "data": {
297
+ "text/plain": [
298
+ "<bound method Module.modules of GPTNeoXForCausalLM(\n",
299
+ " (gpt_neox): GPTNeoXModel(\n",
300
+ " (embed_in): Embedding(51200, 3072)\n",
301
+ " (emb_dropout): Dropout(p=0.0, inplace=False)\n",
302
+ " (layers): ModuleList(\n",
303
+ " (0-29): 30 x GPTNeoXLayer(\n",
304
+ " (input_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
305
+ " (post_attention_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
306
+ " (post_attention_dropout): Dropout(p=0.0, inplace=False)\n",
307
+ " (post_mlp_dropout): Dropout(p=0.0, inplace=False)\n",
308
+ " (attention): GPTNeoXAttention(\n",
309
+ " (rotary_emb): GPTNeoXRotaryEmbedding()\n",
310
+ " (query_key_value): Linear(in_features=3072, out_features=9216, bias=True)\n",
311
+ " (dense): Linear(in_features=3072, out_features=3072, bias=True)\n",
312
+ " (attention_dropout): Dropout(p=0.0, inplace=False)\n",
313
+ " )\n",
314
+ " (mlp): GPTNeoXMLP(\n",
315
+ " (dense_h_to_4h): Linear(in_features=3072, out_features=12288, bias=True)\n",
316
+ " (dense_4h_to_h): Linear(in_features=12288, out_features=3072, bias=True)\n",
317
+ " (act): GELUActivation()\n",
318
+ " )\n",
319
+ " )\n",
320
+ " )\n",
321
+ " (final_layer_norm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
322
+ " )\n",
323
+ " (embed_out): Linear(in_features=3072, out_features=51200, bias=False)\n",
324
+ ")>"
325
+ ]
326
+ },
327
+ "execution_count": 9,
328
+ "metadata": {},
329
+ "output_type": "execute_result"
330
+ }
331
+ ],
332
+ "source": [
333
+ "lora_model2.modules"
334
+ ]
335
+ },
336
+ {
337
+ "cell_type": "code",
338
+ "execution_count": 10,
339
+ "id": "b588088b-1a6b-43d9-b023-3b6193291117",
340
+ "metadata": {},
341
+ "outputs": [],
342
+ "source": [
343
+ "# 保存\n",
344
+ "\n",
345
+ "lora_model2.save_pretrained('merged/spellcheckGPT')"
346
+ ]
347
+ },
348
+ {
349
+ "cell_type": "markdown",
350
+ "id": "d22086c4-7b31-4573-a6f7-1c52c80ccb3d",
351
+ "metadata": {},
352
+ "source": [
353
+ "# 次から"
354
+ ]
355
+ },
356
+ {
357
+ "cell_type": "code",
358
+ "execution_count": 11,
359
+ "id": "faf07b2e-c374-466a-a5f5-fc417820cee6",
360
+ "metadata": {},
361
+ "outputs": [
362
+ {
363
+ "data": {
364
+ "application/vnd.jupyter.widget-view+json": {
365
+ "model_id": "732b45c8e9d049dc93ddf7bccc87bc41",
366
+ "version_major": 2,
367
+ "version_minor": 0
368
+ },
369
+ "text/plain": [
370
+ "Loading checkpoint shards: 0%| | 0/2 [00:00<?, ?it/s]"
371
+ ]
372
+ },
373
+ "metadata": {},
374
+ "output_type": "display_data"
375
+ }
376
+ ],
377
+ "source": [
378
+ "import os\n",
379
+ "import torch\n",
380
+ "from peft import PeftModel, PeftConfig\n",
381
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
382
+ "os.environ[\"CUDA_VISIBLE_DEVICES\"]=\"1\" # これは0, 1, 2のGPUから、2(3番目のGPU)だけ使うという宣言。\n",
383
+ "\n",
384
+ "my_model = 'merged/spellcheckGPT'\n",
385
+ "spellcheckGPT = AutoModelForCausalLM.from_pretrained(my_model,\n",
386
+ " load_in_8bit=True,\n",
387
+ " device_map=\"auto\",)\n",
388
+ "tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=False, padding_size=\"left\", legacy=True)\n",
389
+ "tokenizer.do_lower_case = True "
390
+ ]
391
+ },
392
+ {
393
+ "cell_type": "code",
394
+ "execution_count": 13,
395
+ "id": "32045d37-9a40-47e6-860e-0c521c9ae3b5",
396
+ "metadata": {},
397
+ "outputs": [
398
+ {
399
+ "name": "stdout",
400
+ "output_type": "stream",
401
+ "text": [
402
+ "修正前:空も青く、今日はほとにいい天気ですね。 修正後:空も青く、今日はとても天気がいいですね。\n",
403
+ "修正前:いつれ、私は仙台に戻ります。 修正後:いつれ、私は仙台に戻ります。\n",
404
+ "修正前:私はとっくに修士課程を終了しています。 修正後:私はとっくに修士課程を終了しています。\n"
405
+ ]
406
+ }
407
+ ],
408
+ "source": [
409
+ "\n",
410
+ "# 評価モード\n",
411
+ "spellcheckGPT.eval()\n",
412
+ "\n",
413
+ "#ファインチューニングしたモデルをbest_modelと名付け、再度生成。モデル名がbest_modelに代えていることに注意。太宰的な文章が生成されている。\n",
414
+ "#best_model = trainer.model.cpu()\n",
415
+ "\n",
416
+ "for text in texts:\n",
417
+ " prompt = prompt_infer(text)\n",
418
+ " prompt_ids = tokenizer(prompt, return_tensors = 'pt',add_special_tokens=False).input_ids\n",
419
+ " outputs = spellcheckGPT.generate(\n",
420
+ " input_ids=prompt_ids.to(lora_model.device),\n",
421
+ " #prompt_ids,\n",
422
+ " do_sample=False,\n",
423
+ " max_length=60,\n",
424
+ " num_return_sequences=1,\n",
425
+ " pad_token_id=tokenizer.eos_token_id\n",
426
+ " )\n",
427
+ " #tokenizer.batch_decode(outputs, skip_special_tokens = True)\n",
428
+ " print('\\n'.join(converts(tokenizer.batch_decode(outputs, skip_special_tokens = True))))\n"
429
+ ]
430
+ }
431
+ ],
432
+ "metadata": {
433
+ "kernelspec": {
434
+ "display_name": "Python 3 (ipykernel)",
435
+ "language": "python",
436
+ "name": "python3"
437
+ },
438
+ "language_info": {
439
+ "codemirror_mode": {
440
+ "name": "ipython",
441
+ "version": 3
442
+ },
443
+ "file_extension": ".py",
444
+ "mimetype": "text/x-python",
445
+ "name": "python",
446
+ "nbconvert_exporter": "python",
447
+ "pygments_lexer": "ipython3",
448
+ "version": "3.11.5"
449
+ }
450
+ },
451
+ "nbformat": 4,
452
+ "nbformat_minor": 5
453
+ }
モデルシェア&マージ(V5).ipynb ADDED
@@ -0,0 +1,470 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "52e2911f-c3e0-46f0-b574-a356f5825a23",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "<bound method Module.modules of GPTNeoXForCausalLM(\n",
14
+ " (gpt_neox): GPTNeoXModel(\n",
15
+ " (embed_in): Embedding(51200, 3072)\n",
16
+ " (emb_dropout): Dropout(p=0.0, inplace=False)\n",
17
+ " (layers): ModuleList(\n",
18
+ " (0-29): 30 x GPTNeoXLayer(\n",
19
+ " (input_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
20
+ " (post_attention_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
21
+ " (post_attention_dropout): Dropout(p=0.0, inplace=False)\n",
22
+ " (post_mlp_dropout): Dropout(p=0.0, inplace=False)\n",
23
+ " (attention): GPTNeoXAttention(\n",
24
+ " (rotary_emb): GPTNeoXRotaryEmbedding()\n",
25
+ " (query_key_value): Linear(in_features=3072, out_features=9216, bias=True)\n",
26
+ " (dense): Linear(in_features=3072, out_features=3072, bias=True)\n",
27
+ " (attention_dropout): Dropout(p=0.0, inplace=False)\n",
28
+ " )\n",
29
+ " (mlp): GPTNeoXMLP(\n",
30
+ " (dense_h_to_4h): Linear(in_features=3072, out_features=12288, bias=True)\n",
31
+ " (dense_4h_to_h): Linear(in_features=12288, out_features=3072, bias=True)\n",
32
+ " (act): GELUActivation()\n",
33
+ " )\n",
34
+ " )\n",
35
+ " )\n",
36
+ " (final_layer_norm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
37
+ " )\n",
38
+ " (embed_out): Linear(in_features=3072, out_features=51200, bias=False)\n",
39
+ ")>\n"
40
+ ]
41
+ }
42
+ ],
43
+ "source": [
44
+ "# 利用するGPUを制限\n",
45
+ "import os\n",
46
+ "import torch\n",
47
+ "from peft import PeftModel, PeftConfig\n",
48
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
49
+ "os.environ[\"CUDA_VISIBLE_DEVICES\"]=\"0\" # これは0, 1, 2のGPUから、2(3番目のGPU)だけ使うという宣言。\n",
50
+ "\n",
51
+ "# メインモデル\n",
52
+ "MODEL_NAME = 'line-corporation/japanese-large-lm-3.6b'\n",
53
+ "# モデルの準備\n",
54
+ "model = AutoModelForCausalLM.from_pretrained(\n",
55
+ " MODEL_NAME,\n",
56
+ " load_in_8bit=False, # 注意:8bitで読み込むと結合不可能\n",
57
+ " device_map=\"auto\",\n",
58
+ ")\n",
59
+ "\n",
60
+ "tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=False, padding_size=\"left\", legacy=True)\n",
61
+ "tokenizer.do_lower_case = True \n",
62
+ "\n",
63
+ "print(model.modules)"
64
+ ]
65
+ },
66
+ {
67
+ "cell_type": "code",
68
+ "execution_count": 2,
69
+ "id": "25768347-129c-4570-b9a1-7dff10422049",
70
+ "metadata": {},
71
+ "outputs": [],
72
+ "source": [
73
+ "import os\n",
74
+ "os.chdir('/data/shared_project/GPT')"
75
+ ]
76
+ },
77
+ {
78
+ "cell_type": "code",
79
+ "execution_count": 8,
80
+ "id": "0d93f697-9bf1-4214-ae31-47451edb3e7e",
81
+ "metadata": {},
82
+ "outputs": [
83
+ {
84
+ "name": "stdout",
85
+ "output_type": "stream",
86
+ "text": [
87
+ "<bound method Module.modules of PeftModelForCausalLM(\n",
88
+ " (base_model): LoraModel(\n",
89
+ " (model): GPTNeoXForCausalLM(\n",
90
+ " (gpt_neox): GPTNeoXModel(\n",
91
+ " (embed_in): Embedding(51200, 3072)\n",
92
+ " (emb_dropout): Dropout(p=0.0, inplace=False)\n",
93
+ " (layers): ModuleList(\n",
94
+ " (0-29): 30 x GPTNeoXLayer(\n",
95
+ " (input_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
96
+ " (post_attention_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
97
+ " (post_attention_dropout): Dropout(p=0.0, inplace=False)\n",
98
+ " (post_mlp_dropout): Dropout(p=0.0, inplace=False)\n",
99
+ " (attention): GPTNeoXAttention(\n",
100
+ " (rotary_emb): GPTNeoXRotaryEmbedding()\n",
101
+ " (query_key_value): Linear(\n",
102
+ " in_features=3072, out_features=9216, bias=True\n",
103
+ " (lora_dropout): ModuleDict(\n",
104
+ " (default): Dropout(p=0.05, inplace=False)\n",
105
+ " )\n",
106
+ " (lora_A): ModuleDict(\n",
107
+ " (default): Linear(in_features=3072, out_features=24, bias=False)\n",
108
+ " )\n",
109
+ " (lora_B): ModuleDict(\n",
110
+ " (default): Linear(in_features=24, out_features=9216, bias=False)\n",
111
+ " )\n",
112
+ " (lora_embedding_A): ParameterDict()\n",
113
+ " (lora_embedding_B): ParameterDict()\n",
114
+ " )\n",
115
+ " (dense): Linear(\n",
116
+ " in_features=3072, out_features=3072, bias=True\n",
117
+ " (lora_dropout): ModuleDict(\n",
118
+ " (default): Dropout(p=0.05, inplace=False)\n",
119
+ " )\n",
120
+ " (lora_A): ModuleDict(\n",
121
+ " (default): Linear(in_features=3072, out_features=24, bias=False)\n",
122
+ " )\n",
123
+ " (lora_B): ModuleDict(\n",
124
+ " (default): Linear(in_features=24, out_features=3072, bias=False)\n",
125
+ " )\n",
126
+ " (lora_embedding_A): ParameterDict()\n",
127
+ " (lora_embedding_B): ParameterDict()\n",
128
+ " )\n",
129
+ " (attention_dropout): Dropout(p=0.0, inplace=False)\n",
130
+ " )\n",
131
+ " (mlp): GPTNeoXMLP(\n",
132
+ " (dense_h_to_4h): Linear(in_features=3072, out_features=12288, bias=True)\n",
133
+ " (dense_4h_to_h): Linear(in_features=12288, out_features=3072, bias=True)\n",
134
+ " (act): GELUActivation()\n",
135
+ " )\n",
136
+ " )\n",
137
+ " )\n",
138
+ " (final_layer_norm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
139
+ " )\n",
140
+ " (embed_out): Linear(in_features=3072, out_features=51200, bias=False)\n",
141
+ " )\n",
142
+ " )\n",
143
+ ")>\n"
144
+ ]
145
+ }
146
+ ],
147
+ "source": [
148
+ "# Loraモジュールが入っているフォルダ\n",
149
+ "lora_name = \"lora-rinna-test_sample_V5\"\n",
150
+ "checkpoint = 300\n",
151
+ "\n",
152
+ "# LoRAモデルの準備\n",
153
+ "lora_model = PeftModel.from_pretrained(\n",
154
+ " model, \n",
155
+ " f'{lora_name}/checkpoint-{checkpoint}', \n",
156
+ " device_map=\"auto\"\n",
157
+ ")\n",
158
+ "\n",
159
+ "print(lora_model.modules)\n",
160
+ "\n"
161
+ ]
162
+ },
163
+ {
164
+ "cell_type": "markdown",
165
+ "id": "408c34f4-223d-4874-a610-94b41ddaa41e",
166
+ "metadata": {},
167
+ "source": [
168
+ "# 関数の読み込み"
169
+ ]
170
+ },
171
+ {
172
+ "cell_type": "code",
173
+ "execution_count": 9,
174
+ "id": "5eaf491b-da91-409f-87c2-7f731c569e70",
175
+ "metadata": {},
176
+ "outputs": [
177
+ {
178
+ "name": "stdout",
179
+ "output_type": "stream",
180
+ "text": [
181
+ "本文の文章の誤字、脱字などを含むスペルチェックを行ってください、「チェック:」の後に出力してください。例:修正前:仮名の「ん」で表される音は、後続の音によって などとにる。 チェック:\"にる\"->\"なる\", 。修正前:今日はいい転居ですね! チェック:\n"
182
+ ]
183
+ },
184
+ {
185
+ "data": {
186
+ "text/plain": [
187
+ "['修正前:あなたは今どこにいますか? 修正後:あなたは今どこにいますか?']"
188
+ ]
189
+ },
190
+ "execution_count": 9,
191
+ "metadata": {},
192
+ "output_type": "execute_result"
193
+ }
194
+ ],
195
+ "source": [
196
+ "# プロンプト変換\n",
197
+ "def prompt_infer(original):\n",
198
+ " '''\n",
199
+ " original: 修正前の文章\n",
200
+ "\n",
201
+ " ---\n",
202
+ " prompt_start: コンテクスト(前置き)\n",
203
+ " original_token: 修正前の文章ののトークン、例:修正前\n",
204
+ " revised_token: 修正後の文章のトークン、例:修正後\n",
205
+ " '''\n",
206
+ " prompt_start = '本文の文章の誤字、脱字などを含むスペルチェックを行ってください、「チェック:」の後に出力してください。例:修正前:仮名の「ん」で表される音は、後続の音によって などとにる。 チェック:\"にる\"->\"なる\", 。'\n",
207
+ " #original_token = '修正前'\n",
208
+ " #revised_token = '修正後'\n",
209
+ " return f'{prompt_start}修正前:{original} チェック:'\n",
210
+ "print(prompt_infer('今日はいい転居ですね!'))\n",
211
+ "\n",
212
+ "\n",
213
+ "import re\n",
214
+ "# 出力表示の簡略化\n",
215
+ "def converts(texts):\n",
216
+ " return [re.findall('(修正前:.*)', text)[0]for text in texts]\n",
217
+ "\n",
218
+ "converts(['修正前の文章の誤字、脱字などを含むスペルチェックを行ってください。問題がない場合、そのままの文章を出力してください。修正前:あなたは今どこにいますか? 修正後:あなたは今どこにいますか?'])\n"
219
+ ]
220
+ },
221
+ {
222
+ "cell_type": "code",
223
+ "execution_count": 10,
224
+ "id": "f8b6b4e1-3bb7-42ff-a102-5a3434b212e0",
225
+ "metadata": {},
226
+ "outputs": [
227
+ {
228
+ "data": {
229
+ "text/plain": [
230
+ "['本文の文章の誤字、脱字などを含むスペルチェックを行ってください、「チェック:」の後に出力してください。例:修正前:仮名の「ん」で表される音は、後続の音によって などとにる。 チェック:\"にる\"->\"なる\", 。修正前:空も青く、今日はほとにいい天気ですね。 チェック:',\n",
231
+ " '本文の文章の誤字、脱字などを含むスペルチェックを行ってください、「チェック:」の後に出力してください。例:修正前:仮名の「ん」で表される音は、後続の音によって などと��る。 チェック:\"にる\"->\"なる\", 。修正前:いつれ、私は仙台に戻ります。 チェック:',\n",
232
+ " '本文の文章の誤字、脱字などを含むスペルチェックを行ってください、「チェック:」の後に出力してください。例:修正前:仮名の「ん」で表される音は、後続の音によって などとにる。 チェック:\"にる\"->\"なる\", 。修正前:私はとっくに修士課程を終了しています。 チェック:']"
233
+ ]
234
+ },
235
+ "execution_count": 10,
236
+ "metadata": {},
237
+ "output_type": "execute_result"
238
+ }
239
+ ],
240
+ "source": [
241
+ "texts = ['空も青く、今日はほとにいい天気ですね。', 'いつれ、私は仙台に戻ります。','私はとっくに修士課程を終了しています。']\n",
242
+ "\n",
243
+ "ctexts = [prompt_infer(t) for t in texts]\n",
244
+ "ctexts"
245
+ ]
246
+ },
247
+ {
248
+ "cell_type": "code",
249
+ "execution_count": 11,
250
+ "id": "c39ba5eb-d2ad-408b-8b7f-8f7e2fa1caf5",
251
+ "metadata": {},
252
+ "outputs": [
253
+ {
254
+ "name": "stdout",
255
+ "output_type": "stream",
256
+ "text": [
257
+ "修正前:仮名の「ん」で表される音は、後続の音によって などとにる。 チェック:\"にる\"->\"なる\", 。修正前:空も青く、今日はほとにいい天気ですね。 チェック:\"ほとに\"->\"とても\",\n",
258
+ "修正前:仮名の「ん」で表される音は、後続の音によって などとにる。 チェック:\"にる\"->\"なる\", 。修正前:いつれ、私は仙台に戻ります。 チェック:\"いつれ\"->\"いずれ\",\n",
259
+ "修正前:仮名の「ん」で表される音は、後続の音によって などとにる。 チェック:\"にる\"->\"なる\", 。修正前:私はとっくに修士課程を終了しています。 チェック:\"を\"->\"の\",\n"
260
+ ]
261
+ }
262
+ ],
263
+ "source": [
264
+ "\n",
265
+ "# 評価モード\n",
266
+ "lora_model.eval()\n",
267
+ "tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=False, legacy=True)\n",
268
+ "#ファインチューニングしたモデルをbest_modelと名付け、再度生成。モデル名がbest_modelに代えていることに注意。太宰的な文章が生成されている。\n",
269
+ "#best_model = trainer.model.cpu()\n",
270
+ "\n",
271
+ "for text in texts:\n",
272
+ " prompt = prompt_infer(text)\n",
273
+ " prompt_ids = tokenizer(prompt, return_tensors = 'pt',add_special_tokens=False).input_ids\n",
274
+ " outputs = lora_model.generate(\n",
275
+ " input_ids=prompt_ids.to(lora_model.device),\n",
276
+ " #prompt_ids,\n",
277
+ " do_sample=False,\n",
278
+ " max_length=256,\n",
279
+ " num_return_sequences=1,\n",
280
+ " pad_token_id=tokenizer.eos_token_id\n",
281
+ " )\n",
282
+ " #tokenizer.batch_decode(outputs, skip_special_tokens = True)\n",
283
+ " print('\\n'.join(converts(tokenizer.batch_decode(outputs, skip_special_tokens = True))))\n"
284
+ ]
285
+ },
286
+ {
287
+ "cell_type": "markdown",
288
+ "id": "e458339b-43bc-4c61-89d8-97e973c0ba3f",
289
+ "metadata": {},
290
+ "source": [
291
+ "# モデル結合\n",
292
+ "\n",
293
+ "loraパラメーターをもとのニューラルネットワークに加算し、結合する。"
294
+ ]
295
+ },
296
+ {
297
+ "cell_type": "code",
298
+ "execution_count": 8,
299
+ "id": "a7415bdf-0af0-4596-bc44-4aed4b06e9d1",
300
+ "metadata": {},
301
+ "outputs": [],
302
+ "source": [
303
+ "lora_model2 = lora_model.merge_and_unload()"
304
+ ]
305
+ },
306
+ {
307
+ "cell_type": "code",
308
+ "execution_count": 9,
309
+ "id": "5d627d97-dc39-4674-8881-be06ad0cee9a",
310
+ "metadata": {},
311
+ "outputs": [
312
+ {
313
+ "data": {
314
+ "text/plain": [
315
+ "<bound method Module.modules of GPTNeoXForCausalLM(\n",
316
+ " (gpt_neox): GPTNeoXModel(\n",
317
+ " (embed_in): Embedding(51200, 3072)\n",
318
+ " (emb_dropout): Dropout(p=0.0, inplace=False)\n",
319
+ " (layers): ModuleList(\n",
320
+ " (0-29): 30 x GPTNeoXLayer(\n",
321
+ " (input_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
322
+ " (post_attention_layernorm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
323
+ " (post_attention_dropout): Dropout(p=0.0, inplace=False)\n",
324
+ " (post_mlp_dropout): Dropout(p=0.0, inplace=False)\n",
325
+ " (attention): GPTNeoXAttention(\n",
326
+ " (rotary_emb): GPTNeoXRotaryEmbedding()\n",
327
+ " (query_key_value): Linear(in_features=3072, out_features=9216, bias=True)\n",
328
+ " (dense): Linear(in_features=3072, out_features=3072, bias=True)\n",
329
+ " (attention_dropout): Dropout(p=0.0, inplace=False)\n",
330
+ " )\n",
331
+ " (mlp): GPTNeoXMLP(\n",
332
+ " (dense_h_to_4h): Linear(in_features=3072, out_features=12288, bias=True)\n",
333
+ " (dense_4h_to_h): Linear(in_features=12288, out_features=3072, bias=True)\n",
334
+ " (act): GELUActivation()\n",
335
+ " )\n",
336
+ " )\n",
337
+ " )\n",
338
+ " (final_layer_norm): LayerNorm((3072,), eps=1e-05, elementwise_affine=True)\n",
339
+ " )\n",
340
+ " (embed_out): Linear(in_features=3072, out_features=51200, bias=False)\n",
341
+ ")>"
342
+ ]
343
+ },
344
+ "execution_count": 9,
345
+ "metadata": {},
346
+ "output_type": "execute_result"
347
+ }
348
+ ],
349
+ "source": [
350
+ "lora_model2.modules"
351
+ ]
352
+ },
353
+ {
354
+ "cell_type": "code",
355
+ "execution_count": 10,
356
+ "id": "b588088b-1a6b-43d9-b023-3b6193291117",
357
+ "metadata": {},
358
+ "outputs": [],
359
+ "source": [
360
+ "# 保存\n",
361
+ "\n",
362
+ "lora_model2.save_pretrained('merged/spellcheckGPT')"
363
+ ]
364
+ },
365
+ {
366
+ "cell_type": "markdown",
367
+ "id": "d22086c4-7b31-4573-a6f7-1c52c80ccb3d",
368
+ "metadata": {},
369
+ "source": [
370
+ "# 次から"
371
+ ]
372
+ },
373
+ {
374
+ "cell_type": "code",
375
+ "execution_count": 11,
376
+ "id": "faf07b2e-c374-466a-a5f5-fc417820cee6",
377
+ "metadata": {},
378
+ "outputs": [
379
+ {
380
+ "data": {
381
+ "application/vnd.jupyter.widget-view+json": {
382
+ "model_id": "732b45c8e9d049dc93ddf7bccc87bc41",
383
+ "version_major": 2,
384
+ "version_minor": 0
385
+ },
386
+ "text/plain": [
387
+ "Loading checkpoint shards: 0%| | 0/2 [00:00<?, ?it/s]"
388
+ ]
389
+ },
390
+ "metadata": {},
391
+ "output_type": "display_data"
392
+ }
393
+ ],
394
+ "source": [
395
+ "import os\n",
396
+ "import torch\n",
397
+ "from peft import PeftModel, PeftConfig\n",
398
+ "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
399
+ "os.environ[\"CUDA_VISIBLE_DEVICES\"]=\"1\" # これは0, 1, 2のGPUから、2(3番目のGPU)だけ使うという宣言。\n",
400
+ "\n",
401
+ "my_model = 'merged/spellcheckGPT'\n",
402
+ "spellcheckGPT = AutoModelForCausalLM.from_pretrained(my_model,\n",
403
+ " load_in_8bit=True,\n",
404
+ " device_map=\"auto\",)\n",
405
+ "tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=False, padding_size=\"left\", legacy=True)\n",
406
+ "tokenizer.do_lower_case = True "
407
+ ]
408
+ },
409
+ {
410
+ "cell_type": "code",
411
+ "execution_count": 13,
412
+ "id": "32045d37-9a40-47e6-860e-0c521c9ae3b5",
413
+ "metadata": {},
414
+ "outputs": [
415
+ {
416
+ "name": "stdout",
417
+ "output_type": "stream",
418
+ "text": [
419
+ "修正前:空も青く、今日はほとにいい天気ですね。 修正後:空も青く、今日はとても天気がいいですね。\n",
420
+ "修正前:いつれ、私は仙台に戻ります。 修正後:いつれ、私は仙台に戻ります。\n",
421
+ "修正前:私はとっくに修士課程を終了しています。 修正後:私はとっくに修士課程を終了しています。\n"
422
+ ]
423
+ }
424
+ ],
425
+ "source": [
426
+ "\n",
427
+ "# 評価モード\n",
428
+ "spellcheckGPT.eval()\n",
429
+ "\n",
430
+ "#ファインチューニングしたモデルをbest_modelと名付け、再度生成。モデル名がbest_modelに代えていることに注意。太宰的な文章が生成されている。\n",
431
+ "#best_model = trainer.model.cpu()\n",
432
+ "\n",
433
+ "for text in texts:\n",
434
+ " prompt = prompt_infer(text)\n",
435
+ " prompt_ids = tokenizer(prompt, return_tensors = 'pt',add_special_tokens=False).input_ids\n",
436
+ " outputs = spellcheckGPT.generate(\n",
437
+ " input_ids=prompt_ids.to(lora_model.device),\n",
438
+ " #prompt_ids,\n",
439
+ " do_sample=False,\n",
440
+ " max_length=60,\n",
441
+ " num_return_sequences=1,\n",
442
+ " pad_token_id=tokenizer.eos_token_id\n",
443
+ " )\n",
444
+ " #tokenizer.batch_decode(outputs, skip_special_tokens = True)\n",
445
+ " print('\\n'.join(converts(tokenizer.batch_decode(outputs, skip_special_tokens = True))))\n"
446
+ ]
447
+ }
448
+ ],
449
+ "metadata": {
450
+ "kernelspec": {
451
+ "display_name": "Python 3 (ipykernel)",
452
+ "language": "python",
453
+ "name": "python3"
454
+ },
455
+ "language_info": {
456
+ "codemirror_mode": {
457
+ "name": "ipython",
458
+ "version": 3
459
+ },
460
+ "file_extension": ".py",
461
+ "mimetype": "text/x-python",
462
+ "name": "python",
463
+ "nbconvert_exporter": "python",
464
+ "pygments_lexer": "ipython3",
465
+ "version": "3.11.5"
466
+ }
467
+ },
468
+ "nbformat": 4,
469
+ "nbformat_minor": 5
470
+ }