Upload try_lora.py with huggingface_hub
Browse files- try_lora.py +299 -0
try_lora.py
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import os
|
| 3 |
+
import torch
|
| 4 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, AdamW, default_data_collator, get_linear_schedule_with_warmup, get_cosine_schedule_with_warmup,set_seed
|
| 5 |
+
from peft import LoraConfig, PeftModel, get_peft_model
|
| 6 |
+
import torch.nn.functional as F
|
| 7 |
+
import json
|
| 8 |
+
from datasets import load_dataset
|
| 9 |
+
from torch.utils.data import DataLoader
|
| 10 |
+
from tqdm import tqdm
|
| 11 |
+
import random
|
| 12 |
+
import argparse
|
| 13 |
+
import sys
|
| 14 |
+
# Ensure the src directory is in the Python path
|
| 15 |
+
current_dir = os.path.dirname(__file__)
|
| 16 |
+
src_dir = os.path.abspath(os.path.join(current_dir, '..', '..'))
|
| 17 |
+
if src_dir not in sys.path:
|
| 18 |
+
sys.path.append(src_dir)
|
| 19 |
+
#from src.prompts.prompts import instruction_prompts
|
| 20 |
+
|
| 21 |
+
# import pydevd_pycharm
|
| 22 |
+
# pydevd_pycharm.settrace('9.195.44.45', port=12345, stdoutToServer=True, stderrToServer=True)
|
| 23 |
+
|
| 24 |
+
def parse_arguments(arg_list: list = None):
|
| 25 |
+
parser = argparse.ArgumentParser(description='Lora fine-tuning of base model.')
|
| 26 |
+
parser.add_argument('--seed', type=int, default=42, help='random seed for reproducibility')
|
| 27 |
+
parser.add_argument('--initial_checkpoint', type=str, default="ibm-granite/granite-20b-code-instruct",
|
| 28 |
+
help='Path to the intial checkpoint.')
|
| 29 |
+
parser.add_argument('--training_data_file_path', type=str, default="../../data/generated_data/version_2_1/train_data_version_2_1_anonymized_new_conversation.jsonl",
|
| 30 |
+
help='Path to input training data file.')
|
| 31 |
+
parser.add_argument('--checkpoint_store_dir_path', type=str, default="../../checkpoints_granite/version_2_1/",
|
| 32 |
+
help='path to save the checkpoints.')
|
| 33 |
+
|
| 34 |
+
parser.add_argument('--batch_size_train', type=int, default=1, help='Batch size for training.')
|
| 35 |
+
parser.add_argument('--batch_size_val', type=int, default=1, help='Batch size for Validation.')
|
| 36 |
+
parser.add_argument('--max_length', type=int, default=4000, help='max length of input.')
|
| 37 |
+
parser.add_argument('--initial_lr', type=float, default=2e-5, help='Initial learning rate')
|
| 38 |
+
parser.add_argument('--num_epochs', type=int, default=20, help='number of epochs')
|
| 39 |
+
parser.add_argument('--lora_r', type=int, default=8, help='LoRA rank')
|
| 40 |
+
parser.add_argument('--lora_alpha', type=int, default=32, help='LoRA alpha parameter')
|
| 41 |
+
parser.add_argument('--lora_dropout', type=float, default=0.1, help='LoRA dropout rate')
|
| 42 |
+
parser.add_argument('--target_modules', nargs='+', default= ['c_attn'],
|
| 43 |
+
help='List of target modules')
|
| 44 |
+
if arg_list is None:
|
| 45 |
+
args = parser.parse_args()
|
| 46 |
+
else:
|
| 47 |
+
args = parser.parse_args(arg_list)
|
| 48 |
+
|
| 49 |
+
return args
|
| 50 |
+
|
| 51 |
+
def main():
|
| 52 |
+
|
| 53 |
+
args = parse_arguments()
|
| 54 |
+
set_seed(args.seed)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
initial_checkpoint = args.initial_checkpoint
|
| 58 |
+
training_data_file_path = args.training_data_file_path
|
| 59 |
+
checkpoint_store_dir_path = args.checkpoint_store_dir_path
|
| 60 |
+
initial_lr = args.initial_lr
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
max_length = args.max_length
|
| 64 |
+
batch_size_train = args.batch_size_train
|
| 65 |
+
batch_size_test = args.batch_size_val
|
| 66 |
+
num_epochs = args.num_epochs
|
| 67 |
+
lora_r = args.lora_r
|
| 68 |
+
lora_alpha = args.lora_alpha
|
| 69 |
+
lora_dropout = args.lora_dropout
|
| 70 |
+
target_modules = args.target_modules
|
| 71 |
+
|
| 72 |
+
print("Intial Model: {}".format(initial_checkpoint))
|
| 73 |
+
print("Data path: {}".format(training_data_file_path))
|
| 74 |
+
print("Checkpoint base dir path: {}".format(checkpoint_store_dir_path))
|
| 75 |
+
print("Initial learning rate: {}".format(initial_lr))
|
| 76 |
+
print("LoRA rank: {}".format(lora_r))
|
| 77 |
+
print("LoRA alpha: {}".format(lora_alpha))
|
| 78 |
+
print("LoRA dropout rate: {}".format(lora_dropout))
|
| 79 |
+
print("LoRA Target modules: {}".format(target_modules))
|
| 80 |
+
|
| 81 |
+
tokenizer = AutoTokenizer.from_pretrained(initial_checkpoint)
|
| 82 |
+
dataset = load_dataset('json', data_files=training_data_file_path)
|
| 83 |
+
|
| 84 |
+
if tokenizer.pad_token_id is None:
|
| 85 |
+
tokenizer.pad_token_id = tokenizer.eos_token_id
|
| 86 |
+
|
| 87 |
+
past_context_code = 'past_context_code'
|
| 88 |
+
new_input = 'new_input'
|
| 89 |
+
label_column = 'output'
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
# def get_examples_all_context_granite(examples, only_code=False):
|
| 93 |
+
|
| 94 |
+
# #inputs = [ f"You are given a set of APIs and previously generated Code as context. The task is given a new requirement from Bob modify or expand the given code using the only the provided APIs.\n\nAPIs:\n{apis}\n\nPrevious Conversation Context:\n{past_context_NL}\n\nPrevious Code Context:\n{past_context_code}\n\nInput:\n{new_input}\n"
|
| 95 |
+
# # instruction = """Question:\nYou are an expert Python programmer.\nYou can update existing python code as per the provided instruction.\nYou first try to understand the existing code if provided and then decide where exactly to insert or update the code to make it fulfil the given instruction.\nA set of python functions are also provided that you can call. You cannot alter the functionality of any function.\nEach python function has a description explaining the task it performs.\nUse only simple python commands. You job is to only return the updated code.Do not include any explanation. Do not create your own function names.\nIf a function does not exist use the function called user_task with a parameter describing the task.\nIf Context is also provided for the instruction, then extract user preferences for functions from the context, and use them for answering the instruction.\n\nFunctions:"""
|
| 96 |
+
# instruction = instruction_prompts['zeroshot_prompt']
|
| 97 |
+
# inputs = [ instruction + f"\n\n{apis}\n\nPrevious Conversation Context:\n{past_context_NL}\n\nFollowing is the existing code for you to update:\n{past_context_code}\n\nInput:\n{new_input}\n\nAnswer:\n" for apis, past_context_NL, past_context_code, new_input in zip(examples['apis'], examples['past_context_NL'], examples['past_context_code'], examples['new_input'])]
|
| 98 |
+
|
| 99 |
+
# if only_code == False:
|
| 100 |
+
# targets = ["\nNew NL response:\n" + new_NL_response + "\nUpdated Code:\n" + str(new_code) for new_NL_response, new_code in zip(examples['new_NL_response'],examples['new_code'])]
|
| 101 |
+
# else:
|
| 102 |
+
# targets = ["\nUpdated Code:\n" + str(new_code) for new_code in examples['new_code']]
|
| 103 |
+
|
| 104 |
+
# return inputs, targets
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
def preprocess_function(examples):
|
| 108 |
+
batch_size = len(examples[past_context_code])
|
| 109 |
+
#inputs = [f"<s>[INST] Question : {x} [/INST] \\n Answer : " for x in examples[past_context_code]]
|
| 110 |
+
inputs = [f"\n<|user|>\n You are given a set of APIs and previously generated Code as context. The task is given a new requirement from Bob modify or expand the given code using the provided APIs.\n\nAPIs:\n{apis}\n\nContext:\n{past_context}\n\nInput:\n{new_input} \n<|assistant|>\n " for apis, past_context, new_input in zip(examples['apis'], examples['past_context_code'], examples['new_input'])]
|
| 111 |
+
targets = [str(x) for x in examples[label_column]]
|
| 112 |
+
#inputs, targets = get_examples_all_context(examples)
|
| 113 |
+
|
| 114 |
+
#inputs, targets = get_examples_all_context(examples)
|
| 115 |
+
#inputs, targets = get_examples_all_context_granite(examples, only_code=False)
|
| 116 |
+
model_inputs = tokenizer(inputs)
|
| 117 |
+
|
| 118 |
+
print("Input example:\n{}".format(inputs[0]))
|
| 119 |
+
print("Output example:\n{}".format(targets[0]))
|
| 120 |
+
|
| 121 |
+
input_sizes = [len(tokens) for tokens in model_inputs['input_ids']]
|
| 122 |
+
print("Input sizes {}".format(input_sizes))
|
| 123 |
+
labels = tokenizer(targets, add_special_tokens=False) # don't add bos token because we concatenate with inputs
|
| 124 |
+
label_sizes = [len(tokens) for tokens in labels['input_ids']]
|
| 125 |
+
print("Label sizes {}".format(label_sizes))
|
| 126 |
+
|
| 127 |
+
for i in range(batch_size):
|
| 128 |
+
sample_input_ids = model_inputs["input_ids"][i]
|
| 129 |
+
label_input_ids = labels["input_ids"][i] + [tokenizer.eos_token_id]
|
| 130 |
+
# print(i, sample_input_ids, label_input_ids)
|
| 131 |
+
model_inputs["input_ids"][i] = sample_input_ids + label_input_ids
|
| 132 |
+
labels["input_ids"][i] = [-100] * len(sample_input_ids) + label_input_ids
|
| 133 |
+
model_inputs["attention_mask"][i] = [1] * len(model_inputs["input_ids"][i])
|
| 134 |
+
# print(model_inputs)
|
| 135 |
+
for i in range(batch_size):
|
| 136 |
+
sample_input_ids = model_inputs["input_ids"][i]
|
| 137 |
+
label_input_ids = labels["input_ids"][i]
|
| 138 |
+
model_inputs["input_ids"][i] = [tokenizer.pad_token_id] * (
|
| 139 |
+
max_length - len(sample_input_ids)
|
| 140 |
+
) + sample_input_ids
|
| 141 |
+
model_inputs["attention_mask"][i] = [0] * (max_length - len(sample_input_ids)) + model_inputs[
|
| 142 |
+
"attention_mask"
|
| 143 |
+
][i]
|
| 144 |
+
labels["input_ids"][i] = [-100] * (max_length - len(sample_input_ids)) + label_input_ids
|
| 145 |
+
model_inputs["input_ids"][i] = torch.tensor(model_inputs["input_ids"][i][:max_length])
|
| 146 |
+
model_inputs["attention_mask"][i] = torch.tensor(model_inputs["attention_mask"][i][:max_length])
|
| 147 |
+
labels["input_ids"][i] = torch.tensor(labels["input_ids"][i][:max_length])
|
| 148 |
+
model_inputs["labels"] = labels["input_ids"]
|
| 149 |
+
return model_inputs
|
| 150 |
+
|
| 151 |
+
processed_datasets = dataset.map(
|
| 152 |
+
preprocess_function,
|
| 153 |
+
batched=True,
|
| 154 |
+
num_proc=1,
|
| 155 |
+
remove_columns=dataset["train"].column_names,
|
| 156 |
+
load_from_cache_file=False,
|
| 157 |
+
desc="Running tokenizer on dataset",
|
| 158 |
+
)
|
| 159 |
+
train_dataset = processed_datasets["train"]
|
| 160 |
+
train_dataloader = DataLoader(
|
| 161 |
+
train_dataset, shuffle=True, collate_fn=default_data_collator, batch_size=batch_size_train, pin_memory=True
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
def test_preprocess_function(examples):
|
| 165 |
+
batch_size = len(examples[past_context_code])
|
| 166 |
+
#inputs, targets = get_examples_all_context(examples)
|
| 167 |
+
#inputs, targets = get_examples_all_context_granite(examples)
|
| 168 |
+
inputs = [f"\n<|user|>\n You are given a set of APIs and previously generated Code as context. The task is given a new requirement from Bob modify or expand the given code using the provided APIs.\n\nAPIs:\n{apis}\n\nContext:\n{past_context}\n\nInput:\n{new_input} \n<|assistant|>\n " for apis, past_context, new_input in zip(examples['apis'], examples['past_context_code'], examples['new_input'])]
|
| 169 |
+
model_inputs = tokenizer(inputs)
|
| 170 |
+
# print(model_inputs)
|
| 171 |
+
for i in range(batch_size):
|
| 172 |
+
sample_input_ids = model_inputs["input_ids"][i]
|
| 173 |
+
model_inputs["input_ids"][i] = [tokenizer.pad_token_id] * (
|
| 174 |
+
max_length - len(sample_input_ids)
|
| 175 |
+
) + sample_input_ids
|
| 176 |
+
model_inputs["attention_mask"][i] = [0] * (max_length - len(sample_input_ids)) + model_inputs[
|
| 177 |
+
"attention_mask"
|
| 178 |
+
][i]
|
| 179 |
+
model_inputs["input_ids"][i] = torch.tensor(model_inputs["input_ids"][i][:max_length])
|
| 180 |
+
model_inputs["attention_mask"][i] = torch.tensor(model_inputs["attention_mask"][i][:max_length])
|
| 181 |
+
return model_inputs
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
test_dataset = dataset["train"].map(
|
| 185 |
+
test_preprocess_function,
|
| 186 |
+
batched=True,
|
| 187 |
+
num_proc=1,
|
| 188 |
+
remove_columns=dataset["train"].column_names,
|
| 189 |
+
load_from_cache_file=False,
|
| 190 |
+
desc="Running tokenizer on dataset",
|
| 191 |
+
)
|
| 192 |
+
|
| 193 |
+
test_dataloader = DataLoader(test_dataset, collate_fn=default_data_collator, batch_size=batch_size_test, pin_memory=True)
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 197 |
+
initial_checkpoint,
|
| 198 |
+
torch_dtype=torch.bfloat16,
|
| 199 |
+
attn_implementation="flash_attention_2"
|
| 200 |
+
)
|
| 201 |
+
|
| 202 |
+
print(model)
|
| 203 |
+
|
| 204 |
+
peft_config = LoraConfig(
|
| 205 |
+
r=lora_r, lora_alpha=lora_alpha, lora_dropout=lora_dropout, target_modules= target_modules, bias="none", task_type="CAUSAL_LM"
|
| 206 |
+
)
|
| 207 |
+
|
| 208 |
+
model = get_peft_model(model, peft_config)
|
| 209 |
+
|
| 210 |
+
print("Model loaded successfully!")
|
| 211 |
+
|
| 212 |
+
device = "cuda"
|
| 213 |
+
|
| 214 |
+
#optimizer = AdamW(model.parameters(), lr=3e-4)
|
| 215 |
+
optimizer = AdamW(model.parameters(), lr=initial_lr)
|
| 216 |
+
|
| 217 |
+
# Instantiate scheduler
|
| 218 |
+
lr_scheduler = get_cosine_schedule_with_warmup(
|
| 219 |
+
optimizer=optimizer,
|
| 220 |
+
num_warmup_steps=0.06 * (len(train_dataloader) * num_epochs),
|
| 221 |
+
num_training_steps=(len(train_dataloader) * num_epochs),
|
| 222 |
+
)
|
| 223 |
+
|
| 224 |
+
model.to(device)
|
| 225 |
+
|
| 226 |
+
# model.eval()
|
| 227 |
+
# for step, batch_eval in enumerate(tqdm(test_dataloader)):
|
| 228 |
+
# if step > 5:
|
| 229 |
+
# break
|
| 230 |
+
# batch_eval = {k: v.to(device) for k, v in batch_eval.items()}
|
| 231 |
+
# outputs = model.generate(**batch_eval, max_new_tokens=1024)
|
| 232 |
+
# out = tokenizer.batch_decode(outputs, skip_special_tokens=False)
|
| 233 |
+
# for x in out:
|
| 234 |
+
# print(x)
|
| 235 |
+
# print("#" * 50)
|
| 236 |
+
|
| 237 |
+
for epoch in range(num_epochs):
|
| 238 |
+
model.train()
|
| 239 |
+
total_loss = 0
|
| 240 |
+
for step, batch in enumerate(tqdm(train_dataloader)):
|
| 241 |
+
batch = {k: v.to(device) for k, v in batch.items()}
|
| 242 |
+
# print(batch)
|
| 243 |
+
#print(batch["input_ids"].shape)
|
| 244 |
+
# if step > 5:
|
| 245 |
+
# break
|
| 246 |
+
outputs = model(**batch)
|
| 247 |
+
loss = outputs.loss
|
| 248 |
+
total_loss += loss.detach().float()
|
| 249 |
+
loss.backward()
|
| 250 |
+
#print("Loss {}".format(loss.item()))
|
| 251 |
+
optimizer.step()
|
| 252 |
+
lr_scheduler.step()
|
| 253 |
+
optimizer.zero_grad()
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
print("Total Loss {}".format(total_loss.item()))
|
| 257 |
+
if ((epoch+1) % 1) == 0:
|
| 258 |
+
checkpoint_dir = os.path.join(checkpoint_store_dir_path, f"checkpoint_{epoch}/")
|
| 259 |
+
os.makedirs(checkpoint_dir, exist_ok=True)
|
| 260 |
+
model.save_pretrained(checkpoint_dir)
|
| 261 |
+
model.eval()
|
| 262 |
+
eval_loss = 0
|
| 263 |
+
eval_preds = []
|
| 264 |
+
for step, batch_eval in enumerate(tqdm(test_dataloader)):
|
| 265 |
+
if step > 5:
|
| 266 |
+
break
|
| 267 |
+
batch_eval = {k: v.to(device) for k, v in batch_eval.items()}
|
| 268 |
+
outputs = model.generate(**batch_eval, max_new_tokens=1024)
|
| 269 |
+
out = tokenizer.batch_decode(outputs, skip_special_tokens=True)
|
| 270 |
+
for x in out:
|
| 271 |
+
print(x)
|
| 272 |
+
print("#" * 50)
|
| 273 |
+
# with torch.no_grad():
|
| 274 |
+
# outputs = model(**batch)
|
| 275 |
+
# loss = outputs.loss
|
| 276 |
+
# eval_loss += loss.detach().float()
|
| 277 |
+
# eval_preds.extend(
|
| 278 |
+
# tokenizer.batch_decode(torch.argmax(outputs.logits, -1).detach().cpu().numpy(),
|
| 279 |
+
# skip_special_tokens=True)
|
| 280 |
+
# )
|
| 281 |
+
|
| 282 |
+
# eval_epoch_loss = eval_loss / len(test_dataloader)
|
| 283 |
+
# eval_ppl = torch.exp(eval_epoch_loss)
|
| 284 |
+
train_epoch_loss = total_loss / len(train_dataloader)
|
| 285 |
+
train_ppl = torch.exp(train_epoch_loss)
|
| 286 |
+
#print(f"{epoch=}: {train_ppl=} {train_epoch_loss=} {eval_ppl=} {eval_epoch_loss=}")
|
| 287 |
+
print(f"{epoch=}: {train_ppl=} {train_epoch_loss=}")
|
| 288 |
+
|
| 289 |
+
args_dict = vars(args)
|
| 290 |
+
# Path to the JSON file where the configuration will be saved
|
| 291 |
+
config_file_name = "training_config.json"
|
| 292 |
+
config_file_path = os.path.join(checkpoint_store_dir_path, config_file_name)
|
| 293 |
+
|
| 294 |
+
# Write the configuration dictionary to the JSON file
|
| 295 |
+
with open(config_file_path, "w") as json_file:
|
| 296 |
+
json.dump(args_dict, json_file, indent=4)
|
| 297 |
+
|
| 298 |
+
if __name__ == "_main_":
|
| 299 |
+
main()
|