Artples commited on
Commit
719665e
·
verified ·
1 Parent(s): 1ee5564

Upload Finetuning_NoteBook.ipynb

Browse files
Files changed (1) hide show
  1. Finetuning_NoteBook.ipynb +513 -0
Finetuning_NoteBook.ipynb ADDED
@@ -0,0 +1,513 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "292aa39a",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Installing Required Libraries!"
9
+ ]
10
+ },
11
+ {
12
+ "cell_type": "markdown",
13
+ "id": "8f5ff902",
14
+ "metadata": {},
15
+ "source": [
16
+ "Installing required libraries, including trl, transformers, accelerate, peft, datasets, and bitsandbytes."
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "code",
21
+ "execution_count": null,
22
+ "id": "f74b4a0d",
23
+ "metadata": {},
24
+ "outputs": [],
25
+ "source": [
26
+ "\n",
27
+ "# Checks if PyTorch is installed and installs it if not.\n",
28
+ "try:\n",
29
+ " import torch\n",
30
+ " print(\"PyTorch is installed!\")\n",
31
+ "except ImportError:\n",
32
+ " print(\"PyTorch is not installed.\")\n",
33
+ " !pip install -q torch\n"
34
+ ]
35
+ },
36
+ {
37
+ "cell_type": "code",
38
+ "execution_count": null,
39
+ "id": "d36b37f9",
40
+ "metadata": {},
41
+ "outputs": [],
42
+ "source": [
43
+ "\n",
44
+ "!pip install -q --upgrade \"transformers==4.38.2\"\n",
45
+ "!pip install -q --upgrade \"datasets==2.16.1\"\n",
46
+ "!pip install -q --upgrade \"accelerate==0.26.1\"\n",
47
+ "!pip install -q --upgrade \"evaluate==0.4.1\"\n",
48
+ "!pip install -q --upgrade \"bitsandbytes==0.42.0\"\n",
49
+ "!pip install -q --upgrade \"trl==0.7.11\"\n",
50
+ "!pip install -q --upgrade \"peft==0.8.2\"\n",
51
+ " "
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "markdown",
56
+ "id": "e9f88bba",
57
+ "metadata": {},
58
+ "source": [
59
+ "# Load and Prepare the Dataset"
60
+ ]
61
+ },
62
+ {
63
+ "cell_type": "markdown",
64
+ "id": "df19b148",
65
+ "metadata": {},
66
+ "source": [
67
+ "The dataset is already formatted in a conversational format, which is supported by [trl](https://huggingface.co/docs/trl/index/), and ready for supervised finetuning."
68
+ ]
69
+ },
70
+ {
71
+ "cell_type": "markdown",
72
+ "id": "477e46f4",
73
+ "metadata": {},
74
+ "source": [
75
+ "\n",
76
+ "**Conversational format:**\n",
77
+ "\n",
78
+ "\n",
79
+ "```python {\"messages\": [{\"role\": \"system\", \"content\": \"You are...\"}, {\"role\": \"user\", \"content\": \"...\"}, {\"role\": \"assistant\", \"content\": \"...\"}]}\n",
80
+ "{\"messages\": [{\"role\": \"system\", \"content\": \"You are...\"}, {\"role\": \"user\", \"content\": \"...\"}, {\"role\": \"assistant\", \"content\": \"...\"}]}\n",
81
+ "{\"messages\": [{\"role\": \"system\", \"content\": \"You are...\"}, {\"role\": \"user\", \"content\": \"...\"}, {\"role\": \"assistant\", \"content\": \"...\"}]}\n",
82
+ "```\n"
83
+ ]
84
+ },
85
+ {
86
+ "cell_type": "code",
87
+ "execution_count": null,
88
+ "id": "4f9f3d7a",
89
+ "metadata": {},
90
+ "outputs": [],
91
+ "source": [
92
+ "\n",
93
+ "from datasets import load_dataset\n",
94
+ " \n",
95
+ "# Load dataset from the hub\n",
96
+ "dataset = load_dataset(\"HuggingFaceH4/ultrachat_200k\", split=\"train_sft\")\n",
97
+ " \n",
98
+ "dataset = dataset.shuffle(seed=42)\n",
99
+ " "
100
+ ]
101
+ },
102
+ {
103
+ "cell_type": "markdown",
104
+ "id": "34a66934",
105
+ "metadata": {},
106
+ "source": [
107
+ "## Setting LoRA Config"
108
+ ]
109
+ },
110
+ {
111
+ "cell_type": "markdown",
112
+ "id": "b34de536",
113
+ "metadata": {},
114
+ "source": [
115
+ "The `SFTTrainer` provides native integration with `peft`, simplifying the process of efficiently tuning \n",
116
+ " Language Models (LLMs) using techniques such as [LoRA](\n",
117
+ " https://magazine.sebastianraschka.com/p/practical-tips-for-finetuning-llms). The only requirement is to create \n",
118
+ " the `LoraConfig` and pass it to the `SFTTrainer`. \n",
119
+ " "
120
+ ]
121
+ },
122
+ {
123
+ "cell_type": "code",
124
+ "execution_count": null,
125
+ "id": "648afc1b",
126
+ "metadata": {},
127
+ "outputs": [],
128
+ "source": [
129
+ "\n",
130
+ "from peft import LoraConfig\n",
131
+ "\n",
132
+ "peft_config = LoraConfig(\n",
133
+ " lora_alpha=8,\n",
134
+ " lora_dropout=0.05,\n",
135
+ " r=6,\n",
136
+ " bias=\"none\",\n",
137
+ " target_modules=\"all-linear\",\n",
138
+ " task_type=\"CAUSAL_LM\"\n",
139
+ ")\n",
140
+ " "
141
+ ]
142
+ },
143
+ {
144
+ "cell_type": "markdown",
145
+ "id": "6950f0c4",
146
+ "metadata": {},
147
+ "source": [
148
+ "## Setting the TrainingArguments"
149
+ ]
150
+ },
151
+ {
152
+ "cell_type": "code",
153
+ "execution_count": null,
154
+ "id": "bd721228",
155
+ "metadata": {},
156
+ "outputs": [],
157
+ "source": [
158
+ "\n",
159
+ "# Installing tensorboard to report the metrics\n",
160
+ "!pip install -q tensorboard\n",
161
+ " "
162
+ ]
163
+ },
164
+ {
165
+ "cell_type": "code",
166
+ "execution_count": null,
167
+ "id": "4ced0801",
168
+ "metadata": {},
169
+ "outputs": [],
170
+ "source": [
171
+ "\n",
172
+ "from transformers import TrainingArguments\n",
173
+ "\n",
174
+ "args = TrainingArguments(\n",
175
+ " output_dir=\"temp_/tmp/model\",\n",
176
+ " num_train_epochs=15,\n",
177
+ " per_device_train_batch_size=3,\n",
178
+ " gradient_accumulation_steps=2,\n",
179
+ " gradient_checkpointing=True,\n",
180
+ " gradient_checkpointing_kwargs={'use_reentrant': False},\n",
181
+ " optim=\"adamw_torch_fused\",\n",
182
+ " logging_steps=10,\n",
183
+ " save_strategy='epoch',\n",
184
+ " learning_rate=2e-05,\n",
185
+ " bf16=True,\n",
186
+ " max_grad_norm=0.3,\n",
187
+ " warmup_ratio=0.1,\n",
188
+ " lr_scheduler_type='cosine',\n",
189
+ " report_to='tensorboard', \n",
190
+ " max_steps=-1,\n",
191
+ " seed=42,\n",
192
+ " overwrite_output_dir=True,\n",
193
+ " remove_unused_columns=True\n",
194
+ ")\n",
195
+ " "
196
+ ]
197
+ },
198
+ {
199
+ "cell_type": "markdown",
200
+ "id": "432572ff",
201
+ "metadata": {},
202
+ "source": [
203
+ "## Setting the Supervised Finetuning Trainer (`SFTTrainer`)\n",
204
+ " \n",
205
+ "This `SFTTrainer` is a wrapper around the `transformers.Trainer` class and inherits all of its attributes and methods.\n",
206
+ "The trainer takes care of properly initializing the `PeftModel`. \n",
207
+ " "
208
+ ]
209
+ },
210
+ {
211
+ "cell_type": "code",
212
+ "execution_count": null,
213
+ "id": "e5c50c4d",
214
+ "metadata": {},
215
+ "outputs": [],
216
+ "source": [
217
+ "\n",
218
+ "from trl import SFTTrainer\n",
219
+ "\n",
220
+ "trainer = SFTTrainer(\n",
221
+ " model=model,\n",
222
+ " args=args,\n",
223
+ " train_dataset=dataset,\n",
224
+ " peft_config=peft_config,\n",
225
+ " max_seq_length=2048,\n",
226
+ " tokenizer=tokenizer,\n",
227
+ " packing=True,\n",
228
+ " dataset_kwargs={'add_special_tokens': False, 'append_concat_token': False}\n",
229
+ ")\n"
230
+ ]
231
+ },
232
+ {
233
+ "cell_type": "markdown",
234
+ "id": "f6372ddf",
235
+ "metadata": {},
236
+ "source": [
237
+ "### Starting Training and Saving Model/Tokenizer\n",
238
+ "\n",
239
+ "We start training the model by calling the `train()` method on the trainer instance. This will start the training \n",
240
+ "loop and train the model for `15 epochs`. The model will be automatically saved to the output directory (**'temp_/tmp/model'**)\n",
241
+ "and to the hub in **'User//tmp/model'**. \n",
242
+ " \n",
243
+ " "
244
+ ]
245
+ },
246
+ {
247
+ "cell_type": "code",
248
+ "execution_count": null,
249
+ "id": "90ea4297",
250
+ "metadata": {},
251
+ "outputs": [],
252
+ "source": [
253
+ "\n",
254
+ "\n",
255
+ "model.config.use_cache = False\n",
256
+ "\n",
257
+ "# start training\n",
258
+ "trainer.train()\n",
259
+ "\n",
260
+ "# save the peft model\n",
261
+ "trainer.save_model()\n"
262
+ ]
263
+ },
264
+ {
265
+ "cell_type": "markdown",
266
+ "id": "f2ae5eb4",
267
+ "metadata": {},
268
+ "source": [
269
+ "### Free the GPU Memory to Prepare Merging `LoRA` Adapters with the Base Model\n"
270
+ ]
271
+ },
272
+ {
273
+ "cell_type": "code",
274
+ "execution_count": null,
275
+ "id": "a7524f47",
276
+ "metadata": {},
277
+ "outputs": [],
278
+ "source": [
279
+ "\n",
280
+ "\n",
281
+ "# Free the GPU memory\n",
282
+ "del model\n",
283
+ "del trainer\n",
284
+ "torch.cuda.empty_cache()\n"
285
+ ]
286
+ },
287
+ {
288
+ "cell_type": "markdown",
289
+ "id": "a67f6349",
290
+ "metadata": {},
291
+ "source": [
292
+ "## Merging LoRA Adapters into the Original Model\n",
293
+ "\n",
294
+ "While utilizing `LoRA`, we focus on training the adapters rather than the entire model. Consequently, during the \n",
295
+ "model saving process, only the `adapter weights` are preserved, not the complete model. If we wish to save the \n",
296
+ "entire model for easier usage with Text Generation Inference, we can incorporate the adapter weights into the model \n",
297
+ "weights. This can be achieved using the `merge_and_unload` method. Following this, the model can be saved using the \n",
298
+ "`save_pretrained` method. The result is a default model that is ready for inference.\n"
299
+ ]
300
+ },
301
+ {
302
+ "cell_type": "code",
303
+ "execution_count": null,
304
+ "id": "ba375754",
305
+ "metadata": {},
306
+ "outputs": [],
307
+ "source": [
308
+ "\n",
309
+ "import torch\n",
310
+ "from peft import AutoPeftModelForCausalLM\n",
311
+ "\n",
312
+ "# Load Peft model on CPU\n",
313
+ "model = AutoPeftModelForCausalLM.from_pretrained(\n",
314
+ " \"temp_/tmp/model\",\n",
315
+ " torch_dtype=torch.float16,\n",
316
+ " low_cpu_mem_usage=True\n",
317
+ ")\n",
318
+ " \n",
319
+ "# Merge LoRA with the base model and save\n",
320
+ "merged_model = model.merge_and_unload()\n",
321
+ "merged_model.save_pretrained(\"/tmp/model\", safe_serialization=True, max_shard_size=\"2GB\")\n",
322
+ "tokenizer.save_pretrained(\"/tmp/model\")\n"
323
+ ]
324
+ },
325
+ {
326
+ "cell_type": "markdown",
327
+ "id": "1cdbbc86",
328
+ "metadata": {},
329
+ "source": [
330
+ "### Copy all result folders from 'temp_/tmp/model' to '/tmp/model'"
331
+ ]
332
+ },
333
+ {
334
+ "cell_type": "code",
335
+ "execution_count": null,
336
+ "id": "3254f6a5",
337
+ "metadata": {},
338
+ "outputs": [],
339
+ "source": [
340
+ "\n",
341
+ "import os\n",
342
+ "import shutil\n",
343
+ "\n",
344
+ "source_folder = \"temp_/tmp/model\"\n",
345
+ "destination_folder = \"/tmp/model\"\n",
346
+ "os.makedirs(destination_folder, exist_ok=True)\n",
347
+ "for item in os.listdir(source_folder):\n",
348
+ " item_path = os.path.join(source_folder, item)\n",
349
+ " if os.path.isdir(item_path):\n",
350
+ " destination_path = os.path.join(destination_folder, item)\n",
351
+ " shutil.copytree(item_path, destination_path)\n"
352
+ ]
353
+ },
354
+ {
355
+ "cell_type": "markdown",
356
+ "id": "38468ef8",
357
+ "metadata": {},
358
+ "source": [
359
+ "### Generating a model card (README.md)"
360
+ ]
361
+ },
362
+ {
363
+ "cell_type": "code",
364
+ "execution_count": null,
365
+ "id": "aea8f916",
366
+ "metadata": {},
367
+ "outputs": [],
368
+ "source": [
369
+ "\n",
370
+ "card = '''\n",
371
+ "---\n",
372
+ "license: apache-2.0\n",
373
+ "tags:\n",
374
+ "- generated_from_trainer\n",
375
+ "- mistralai/Mistral\n",
376
+ "- PyTorch\n",
377
+ "- transformers\n",
378
+ "- trl\n",
379
+ "- peft\n",
380
+ "- tensorboard\n",
381
+ "base_model: mistralai/Mistral-[]\n",
382
+ "widget:\n",
383
+ " - example_title: Pirate!\n",
384
+ " messages:\n",
385
+ " - role: system\n",
386
+ " content: You are a pirate chatbot who always responds with Arr!\n",
387
+ " - role: user\n",
388
+ " content: \"There's a llama on my lawn, how can I get rid of him?\"\n",
389
+ " output:\n",
390
+ " text: >-\n",
391
+ " Arr! 'Tis a puzzlin' matter, me hearty! A llama on yer lawn be a rare\n",
392
+ " sight, but I've got a plan that might help ye get rid of 'im. Ye'll need\n",
393
+ " to gather some carrots and hay, and then lure the llama away with the\n",
394
+ " promise of a tasty treat. Once he's gone, ye can clean up yer lawn and\n",
395
+ " enjoy the peace and quiet once again. But beware, me hearty, for there\n",
396
+ " may be more llamas where that one came from! Arr!\n",
397
+ "model-index:\n",
398
+ "- name: /tmp/model\n",
399
+ " results: []\n",
400
+ "datasets:\n",
401
+ "- HuggingFaceH4/ultrachat_200k\n",
402
+ "language:\n",
403
+ "- en\n",
404
+ "pipeline_tag: text-generation\n",
405
+ "---\n",
406
+ "\n",
407
+ "# Model Card for /tmp/model:\n",
408
+ "\n",
409
+ "**/tmp/model** is a language model that is trained to act as helpful assistant. It is a finetuned version of [mistralai/Mistral-[]](https://huggingface.co/mistralai/Mistral-[]) that was trained using `SFTTrainer` on publicly available dataset [\n",
410
+ "HuggingFaceH4/ultrachat_200k](https://huggingface.co/datasets/HuggingFaceH4/ultrachat_200k).\n",
411
+ "\n",
412
+ "## Training Procedure:\n",
413
+ "\n",
414
+ "The training code used to create this model was generated by [Menouar/LLM-FineTuning-Notebook-Generator](https://huggingface.co/spaces/Menouar/LLM-FineTuning-Notebook-Generator).\n",
415
+ "\n",
416
+ "\n",
417
+ "\n",
418
+ "## Training hyperparameters\n",
419
+ "\n",
420
+ "The following hyperparameters were used during the training:\n",
421
+ "\n",
422
+ "\n",
423
+ "'''\n",
424
+ "\n",
425
+ "with open(\"/tmp/model/README.md\", \"w\") as f:\n",
426
+ " f.write(card)\n",
427
+ "\n",
428
+ "args_dict = vars(args)\n",
429
+ "\n",
430
+ "with open(\"/tmp/model/README.md\", \"a\") as f:\n",
431
+ " for k, v in args_dict.items():\n",
432
+ " f.write(f\"- {k}: {v}\")\n",
433
+ " f.write(\"\\n \\n\")\n"
434
+ ]
435
+ },
436
+ {
437
+ "cell_type": "markdown",
438
+ "id": "9088a475",
439
+ "metadata": {},
440
+ "source": [
441
+ "## Login to HF"
442
+ ]
443
+ },
444
+ {
445
+ "cell_type": "markdown",
446
+ "id": "c3359fe7",
447
+ "metadata": {},
448
+ "source": [
449
+ "Replace `HF_TOKEN` with a valid token in order to push **'/tmp/model'** to `huggingface_hub`."
450
+ ]
451
+ },
452
+ {
453
+ "cell_type": "code",
454
+ "execution_count": null,
455
+ "id": "4af7ed8e",
456
+ "metadata": {},
457
+ "outputs": [],
458
+ "source": [
459
+ "\n",
460
+ "# Install huggingface_hub\n",
461
+ "!pip install -q huggingface_hub\n",
462
+ " \n",
463
+ "from huggingface_hub import login\n",
464
+ " \n",
465
+ "login(\n",
466
+ " token='HF_TOKEN',\n",
467
+ " add_to_git_credential=True\n",
468
+ ")\n",
469
+ " "
470
+ ]
471
+ },
472
+ {
473
+ "cell_type": "markdown",
474
+ "id": "08681a27",
475
+ "metadata": {},
476
+ "source": [
477
+ "## Pushing '/tmp/model' to the Hugging Face account."
478
+ ]
479
+ },
480
+ {
481
+ "cell_type": "code",
482
+ "execution_count": null,
483
+ "id": "9a3930f9",
484
+ "metadata": {},
485
+ "outputs": [],
486
+ "source": [
487
+ "\n",
488
+ "from huggingface_hub import HfApi, HfFolder, Repository\n",
489
+ "\n",
490
+ "# Instantiate the HfApi class\n",
491
+ "api = HfApi()\n",
492
+ "\n",
493
+ "# Our Hugging Face repository\n",
494
+ "repo_name = \"/tmp/model\"\n",
495
+ "\n",
496
+ "# Create a repository on the Hugging Face Hub\n",
497
+ "repo = api.create_repo(token=HfFolder.get_token(), repo_type=\"model\", repo_id=repo_name)\n",
498
+ "\n",
499
+ "api.upload_folder(\n",
500
+ " folder_path=\"/tmp/model\",\n",
501
+ " repo_id=repo.repo_id\n",
502
+ ")\n"
503
+ ]
504
+ }
505
+ ],
506
+ "metadata": {
507
+ "language_info": {
508
+ "name": "python"
509
+ }
510
+ },
511
+ "nbformat": 4,
512
+ "nbformat_minor": 5
513
+ }