menouar commited on
Commit
611507d
·
1 Parent(s): f5d0e7d

Create automatically a README.md (HF model card)

Browse files
app.py CHANGED
@@ -2,6 +2,7 @@ from typing import Any
2
 
3
  from nbconvert import HTMLExporter
4
 
 
5
  from utils.notebook_generator import *
6
  from utils.components_creator import *
7
 
@@ -68,10 +69,6 @@ def change_model_selection(model_id):
68
  return None
69
 
70
 
71
- def handle_push_to_hub(value):
72
- return gr.Textbox(visible=value)
73
-
74
-
75
  def check_valid_input(value):
76
  if isinstance(value, str):
77
  return value and value.strip()
@@ -124,6 +121,7 @@ def generate_code(components: dict[Component, Any]):
124
  model_value = get_value(components, MODEL_SELECTION_ID)
125
  should_login = should_login_to_hf_model(model_value)
126
 
 
127
  if not check_valid_input(model_value):
128
  gr.Warning("No model is selected!")
129
  else:
@@ -192,6 +190,12 @@ def generate_code(components: dict[Component, Any]):
192
 
193
  merge_model_cells(notebook['cells'], output_dir)
194
 
 
 
 
 
 
 
195
  if push_to_hub:
196
  if not should_login:
197
  create_login_hf_cells(notebook['cells'])
@@ -287,8 +291,6 @@ with gr.Blocks(css=css, theme=gr.themes.Soft(text_size='lg', font=["monospace"],
287
  with centered_column():
288
  output_dir_cmp, push_to_hub_cmp = add_outputs()
289
  all_components.update({output_dir_cmp, push_to_hub_cmp})
290
- repo_name_cmp = add_hf_repo_cmp()
291
- all_components.update({repo_name_cmp})
292
  with centered_column():
293
  all_components.update(add_outputs1())
294
 
@@ -317,12 +319,6 @@ with gr.Blocks(css=css, theme=gr.themes.Soft(text_size='lg', font=["monospace"],
317
  outputs=version_selection
318
  )
319
 
320
- push_to_hub_cmp.change(
321
- fn=handle_push_to_hub,
322
- inputs=push_to_hub_cmp,
323
- outputs=repo_name_cmp
324
- )
325
-
326
  demo.launch(allowed_paths=["/"])
327
 
328
  # Upload metrics to the hub....
 
2
 
3
  from nbconvert import HTMLExporter
4
 
5
+ from utils.create_info_files import create_hf_card
6
  from utils.notebook_generator import *
7
  from utils.components_creator import *
8
 
 
69
  return None
70
 
71
 
 
 
 
 
72
  def check_valid_input(value):
73
  if isinstance(value, str):
74
  return value and value.strip()
 
121
  model_value = get_value(components, MODEL_SELECTION_ID)
122
  should_login = should_login_to_hf_model(model_value)
123
 
124
+ version_value = ""
125
  if not check_valid_input(model_value):
126
  gr.Warning("No model is selected!")
127
  else:
 
190
 
191
  merge_model_cells(notebook['cells'], output_dir)
192
 
193
+ create_readme = get_value(components, README_ID)
194
+ if create_readme:
195
+ create_hf_card(notebook['cells'], name=output_dir, base_model_name=model_value,
196
+ base_model_version=version_value,
197
+ dataset_name=dataset_value, output_dir=output_dir, report_to=report_to)
198
+
199
  if push_to_hub:
200
  if not should_login:
201
  create_login_hf_cells(notebook['cells'])
 
291
  with centered_column():
292
  output_dir_cmp, push_to_hub_cmp = add_outputs()
293
  all_components.update({output_dir_cmp, push_to_hub_cmp})
 
 
294
  with centered_column():
295
  all_components.update(add_outputs1())
296
 
 
319
  outputs=version_selection
320
  )
321
 
 
 
 
 
 
 
322
  demo.launch(allowed_paths=["/"])
323
 
324
  # Upload metrics to the hub....
utils/__init__.py CHANGED
@@ -41,6 +41,8 @@ REPOSITORY_NAME_ID = "repo_id"
41
 
42
  REPORT_TO_ID = "report_to"
43
 
 
 
44
  MAX_SEQ_LENGTH_ID = "max_seq_length"
45
  PACKING_ID = "packing"
46
 
 
41
 
42
  REPORT_TO_ID = "report_to"
43
 
44
+ README_ID = "readme"
45
+
46
  MAX_SEQ_LENGTH_ID = "max_seq_length"
47
  PACKING_ID = "packing"
48
 
utils/components_creator.py CHANGED
@@ -201,8 +201,13 @@ def add_outputs1() -> Set[Component]:
201
  "'comet_ml', 'mlflow', 'tensorboard' and 'wandb'. Use 'all' to report to all integrations installed, "
202
  "'none' for no integrations."
203
  )
 
 
 
 
204
  out_components: Set[Component] = set()
205
  out_components.add(report_to)
 
206
  return out_components
207
 
208
 
 
201
  "'comet_ml', 'mlflow', 'tensorboard' and 'wandb'. Use 'all' to report to all integrations installed, "
202
  "'none' for no integrations."
203
  )
204
+ create_readme = gr.Checkbox(label="Automatically Generate a README.md", value=True, interactive=True,
205
+ info="Choose whether to automatically generate a model card (README.md) or not.",
206
+ elem_id=README_ID)
207
+
208
  out_components: Set[Component] = set()
209
  out_components.add(report_to)
210
+ out_components.add(create_readme)
211
  return out_components
212
 
213
 
utils/create_info_files.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import nbformat as nbf
2
+
3
+
4
+ def create_hf_card(cells, name, base_model_name, base_model_version, dataset_name, output_dir, report_to):
5
+ text = f"""
6
+ card = '''
7
+ ---
8
+ license: apache-2.0
9
+ tags:
10
+ - generated_from_trainer
11
+ - {base_model_name}
12
+ - PyTorch
13
+ - transformers
14
+ - trl
15
+ - peft
16
+ - {report_to}
17
+ base_model: {base_model_name}-{base_model_version}
18
+ widget:
19
+ - example_title: Pirate!
20
+ messages:
21
+ - role: system
22
+ content: You are a pirate chatbot who always responds with Arr!
23
+ - role: user
24
+ content: "There's a llama on my lawn, how can I get rid of him?"
25
+ output:
26
+ text: >-
27
+ Arr! 'Tis a puzzlin' matter, me hearty! A llama on yer lawn be a rare
28
+ sight, but I've got a plan that might help ye get rid of 'im. Ye'll need
29
+ to gather some carrots and hay, and then lure the llama away with the
30
+ promise of a tasty treat. Once he's gone, ye can clean up yer lawn and
31
+ enjoy the peace and quiet once again. But beware, me hearty, for there
32
+ may be more llamas where that one came from! Arr!
33
+ model-index:
34
+ - name: {name}
35
+ results: []
36
+ datasets:
37
+ - {dataset_name}
38
+ language:
39
+ - en
40
+ pipeline_tag: text-generation
41
+ ---
42
+
43
+ # Model Card for {name}:
44
+
45
+ **{name}** is a language model that is trained to act as helpful assistant. It is a finetuned version of [{base_model_name}-{base_model_version}](https://huggingface.co/{base_model_name}-{base_model_version}) that was trained using SFTTrainer on of publicly available dataset [
46
+ {dataset_name}](https://huggingface.co/datasets/{dataset_name}).
47
+
48
+ ## Training Procedure:
49
+
50
+ 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).
51
+
52
+
53
+
54
+ ## Training hyperparameters
55
+
56
+ The following hyperparameters were used during the training:
57
+
58
+
59
+ '''
60
+
61
+ with open("{output_dir}/README.md", "w") as f:
62
+ f.write(card)
63
+
64
+ args_dict = vars(args)
65
+
66
+ with open("{output_dir}/README.md", "a") as f:
67
+ for k, v in args_dict.items():
68
+ f.write(f"- {{k}}: {{v}}")
69
+ f.write("\\n \\n")
70
+ """
71
+ title = """### Generating a model card (README.md)"""
72
+ cells.append(nbf.v4.new_markdown_cell(title))
73
+ code_cell = nbf.v4.new_code_cell(text)
74
+ cells.append(code_cell)
utils/notebook_generator.py CHANGED
@@ -61,10 +61,10 @@ def create_login_hf_cells(cells: list, should_login: bool = False, model_name: O
61
  text_cell = nbf.v4.new_markdown_cell(
62
  "### Login to HF")
63
 
64
- text_1 = "Login with your `HF_TOKEN` in order to push the finetuned model to `huggingface_hub`."
65
 
66
  if should_login:
67
- text_1 = f"Login with your `HF_TOKEN` in order to load **{model_name}** from `huggingface_hub`."
68
 
69
  text_cell1 = nbf.v4.new_markdown_cell(text_1)
70
  code = """
@@ -167,7 +167,7 @@ This process involves two key steps:
167
 
168
  1. **LLM Quantization:**
169
  - We first load the selected large language model (LLM).
170
- - We then use the "bitsandbytes" library to quantize the model, which can significantly reduce its memory footprint.
171
 
172
  > **Note:** The memory requirements of the model scale with its size. For instance, a 7B parameter model may require
173
  a 24GB GPU for fine-tuning.
@@ -228,7 +228,7 @@ def create_training_args_cells(cells: list, epochs, max_steps, logging_steps, pe
228
  save_strategy, gradient_accumulation_steps, gradient_checkpointing,
229
  learning_rate, max_grad_norm, warmup_ratio, lr_scheduler_type, output_dir,
230
  report_to, seed):
231
- text_cell = nbf.v4.new_markdown_cell("### TrainingArguments")
232
  to_install = None
233
  if report_to == "all":
234
  to_install = "azure_ml comet_ml mlflow tensorboard wandb"
@@ -238,8 +238,7 @@ def create_training_args_cells(cells: list, epochs, max_steps, logging_steps, pe
238
  gradient_checkpointing_kwargs = {"use_reentrant": False}
239
 
240
  code_report = f"""
241
- # Installing {to_install} to report the metrics
242
-
243
  !pip install -q {to_install}
244
  """
245
 
@@ -278,7 +277,7 @@ args = TrainingArguments(
278
 
279
  def create_sft_trainer_cells(cells: list, max_seq_length, packing):
280
  text_cell = nbf.v4.new_markdown_cell(
281
- """### Supervised Finetuning Trainer (SFT Trainer)
282
 
283
  This `SFTTrainer` is a wrapper around the `transformers.Trainer` class and inherits all of its attributes and methods.
284
  The trainer takes care of properly initializing the `PeftModel`.
@@ -308,7 +307,7 @@ trainer = SFTTrainer(
308
 
309
  def create_start_training_cells(cells: list, epochs, max_steps, push_to_hub, output_dir):
310
  if push_to_hub:
311
- save_txt = "and to the hub."
312
  else:
313
  save_txt = "."
314
 
@@ -320,7 +319,7 @@ def create_start_training_cells(cells: list, epochs, max_steps, push_to_hub, out
320
  f"""### Starting Training and Saving Model/Tokenizer
321
 
322
  We start training the model by calling the `train()` method on the trainer instance. This will start the training
323
- loop and train the model for `{epoch_str}`. The model will be automatically saved the output directory(temp_{output_dir})
324
  {save_txt}
325
 
326
  """)
@@ -342,7 +341,8 @@ trainer.save_model()
342
 
343
  def create_free_gpu_cells(cells: list):
344
  text_cell = nbf.v4.new_markdown_cell(
345
- """### Free the GPU Memory for Merging `PeftModel`""")
 
346
 
347
  code = f"""
348
 
@@ -358,11 +358,11 @@ torch.cuda.empty_cache()
358
 
359
  def create_merge_lora_cells(cells: list, output_dir):
360
  text_cell = nbf.v4.new_markdown_cell(
361
- """### Merge LoRA adapter in to the Original Model
362
 
363
  While utilizing `LoRA`, we focus on training the adapters rather than the entire model. Consequently, during the
364
  model saving process, only the `adapter weights` are preserved, not the complete model. If we wish to save the
365
- entire model for easier usage with Text Generation Inference, you can incorporate the adapter weights into the model
366
  weights. This can be achieved using the `merge_and_unload` method. Following this, the model can be saved using the
367
  `save_pretrained` method. The result is a default model that is ready for inference.
368
  """)
@@ -378,7 +378,7 @@ model = AutoPeftModelForCausalLM.from_pretrained(
378
  low_cpu_mem_usage=True
379
  )
380
 
381
- # Merge LoRA and base model and save
382
  merged_model = model.merge_and_unload()
383
  merged_model.save_pretrained("{output_dir}", safe_serialization=True, max_shard_size="2GB")
384
  tokenizer.save_pretrained("{output_dir}")
@@ -396,23 +396,17 @@ def merge_model_cells(cells: list, output_dir):
396
  import os
397
  import shutil
398
 
399
- # Specify the source folder and the destination folder
400
  source_folder = "temp_{output_dir}"
401
  destination_folder = "{output_dir}"
402
 
403
- # Create the destination folder if it doesn't exist
404
  os.makedirs(destination_folder, exist_ok=True)
405
 
406
- # Iterate over the files and subfolders in the source folder
407
  for item in os.listdir(source_folder):
408
  item_path = os.path.join(source_folder, item)
409
 
410
- # Check if it's a subfolder (and not a file)
411
  if os.path.isdir(item_path):
412
- # Specify the destination path
413
  destination_path = os.path.join(destination_folder, item)
414
 
415
- # Copy the subfolder to the destination folder
416
  shutil.copytree(item_path, destination_path)
417
  """
418
 
@@ -422,7 +416,7 @@ for item in os.listdir(source_folder):
422
 
423
 
424
  def push_to_hub_cells(cells: list, output_dir):
425
- text = f"Push '{output_dir}' to your Hugging Face account."
426
  code = f"""
427
  from huggingface_hub import HfApi, HfFolder, Repository
428
 
@@ -437,8 +431,7 @@ repo = api.create_repo(token=HfFolder.get_token(), repo_type="model", repo_id=re
437
 
438
  api.upload_folder(
439
  folder_path="{output_dir}",
440
- repo_id=repo.repo_id,
441
- repo_type="model"
442
  )
443
  """
444
  code_cell = nbf.v4.new_code_cell(code)
 
61
  text_cell = nbf.v4.new_markdown_cell(
62
  "### Login to HF")
63
 
64
+ text_1 = "Login with our `HF_TOKEN` in order to push the finetuned model to `huggingface_hub`."
65
 
66
  if should_login:
67
+ text_1 = f"Login with our `HF_TOKEN` in order to load **{model_name}** from `huggingface_hub`."
68
 
69
  text_cell1 = nbf.v4.new_markdown_cell(text_1)
70
  code = """
 
167
 
168
  1. **LLM Quantization:**
169
  - We first load the selected large language model (LLM).
170
+ - We then use the `bitsandbytes` library to quantize the model, which can significantly reduce its memory footprint.
171
 
172
  > **Note:** The memory requirements of the model scale with its size. For instance, a 7B parameter model may require
173
  a 24GB GPU for fine-tuning.
 
228
  save_strategy, gradient_accumulation_steps, gradient_checkpointing,
229
  learning_rate, max_grad_norm, warmup_ratio, lr_scheduler_type, output_dir,
230
  report_to, seed):
231
+ text_cell = nbf.v4.new_markdown_cell("### Setting the TrainingArguments")
232
  to_install = None
233
  if report_to == "all":
234
  to_install = "azure_ml comet_ml mlflow tensorboard wandb"
 
238
  gradient_checkpointing_kwargs = {"use_reentrant": False}
239
 
240
  code_report = f"""
241
+ # Installing {to_install} to report the metrics
 
242
  !pip install -q {to_install}
243
  """
244
 
 
277
 
278
  def create_sft_trainer_cells(cells: list, max_seq_length, packing):
279
  text_cell = nbf.v4.new_markdown_cell(
280
+ """### Setting the Supervised Finetuning Trainer (`SFTTrainer`)
281
 
282
  This `SFTTrainer` is a wrapper around the `transformers.Trainer` class and inherits all of its attributes and methods.
283
  The trainer takes care of properly initializing the `PeftModel`.
 
307
 
308
  def create_start_training_cells(cells: list, epochs, max_steps, push_to_hub, output_dir):
309
  if push_to_hub:
310
+ save_txt = f"and to the hub in 'User/{output_dir}'."
311
  else:
312
  save_txt = "."
313
 
 
319
  f"""### Starting Training and Saving Model/Tokenizer
320
 
321
  We start training the model by calling the `train()` method on the trainer instance. This will start the training
322
+ loop and train the model for `{epoch_str}`. The model will be automatically saved to the output directory ('temp_{output_dir}')
323
  {save_txt}
324
 
325
  """)
 
341
 
342
  def create_free_gpu_cells(cells: list):
343
  text_cell = nbf.v4.new_markdown_cell(
344
+ """### Free the GPU Memory to Prepare for the Merging of the `PerfModel`
345
+ """)
346
 
347
  code = f"""
348
 
 
358
 
359
  def create_merge_lora_cells(cells: list, output_dir):
360
  text_cell = nbf.v4.new_markdown_cell(
361
+ """### Merging LoRa Adapters into the Original Model
362
 
363
  While utilizing `LoRA`, we focus on training the adapters rather than the entire model. Consequently, during the
364
  model saving process, only the `adapter weights` are preserved, not the complete model. If we wish to save the
365
+ entire model for easier usage with Text Generation Inference, we can incorporate the adapter weights into the model
366
  weights. This can be achieved using the `merge_and_unload` method. Following this, the model can be saved using the
367
  `save_pretrained` method. The result is a default model that is ready for inference.
368
  """)
 
378
  low_cpu_mem_usage=True
379
  )
380
 
381
+ # Merge LoRA with the base model and save
382
  merged_model = model.merge_and_unload()
383
  merged_model.save_pretrained("{output_dir}", safe_serialization=True, max_shard_size="2GB")
384
  tokenizer.save_pretrained("{output_dir}")
 
396
  import os
397
  import shutil
398
 
 
399
  source_folder = "temp_{output_dir}"
400
  destination_folder = "{output_dir}"
401
 
 
402
  os.makedirs(destination_folder, exist_ok=True)
403
 
 
404
  for item in os.listdir(source_folder):
405
  item_path = os.path.join(source_folder, item)
406
 
 
407
  if os.path.isdir(item_path):
 
408
  destination_path = os.path.join(destination_folder, item)
409
 
 
410
  shutil.copytree(item_path, destination_path)
411
  """
412
 
 
416
 
417
 
418
  def push_to_hub_cells(cells: list, output_dir):
419
+ text = f"### Pushing '{output_dir}' to our Hugging Face account."
420
  code = f"""
421
  from huggingface_hub import HfApi, HfFolder, Repository
422
 
 
431
 
432
  api.upload_folder(
433
  folder_path="{output_dir}",
434
+ repo_id=repo.repo_id
 
435
  )
436
  """
437
  code_cell = nbf.v4.new_code_cell(code)