1earner1 commited on
Commit
49e28f9
·
verified ·
1 Parent(s): 561162a

Upload run_unsloth.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. run_unsloth.py +366 -0
run_unsloth.py ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from unsloth import FastLanguageModel
2
+ import torch
3
+ import json
4
+ max_seq_length = 2048 # Choose any! We auto support RoPE Scaling internally!
5
+ dtype = None # None for auto detection. Float16 for Tesla T4, V100, Bfloat16 for Ampere+
6
+ load_in_4bit = False # Use 4bit quantization to reduce memory usage. Can be False.
7
+ from huggingface_hub import hf_hub_download
8
+
9
+ model_name = "Qwen/Qwen1.5-7B"
10
+ cache_path = hf_hub_download(repo_id=model_name, filename="config.json")
11
+ print(cache_path)
12
+
13
+ model, tokenizer = FastLanguageModel.from_pretrained(
14
+ model_name = "Qwen/Qwen2.5-Coder-7B-Instruct", #"unsloth/Qwen2.5-Coder-7B-Instruct",
15
+ use_cache=True,
16
+ cache_dir = "/home/cse/msr/csy227517/.cache/huggingface/hub/models--Qwen--Qwen1.5-7B/snapshots/831096e3a59a0789a541415da25ef195ceb802fe/",
17
+ max_seq_length = max_seq_length,
18
+ dtype = dtype,
19
+ load_in_4bit = load_in_4bit,
20
+ # token = "hf_...", # use one if using gated models like meta-llama/Llama-2-7b-hf
21
+ )
22
+
23
+
24
+ model = FastLanguageModel.get_peft_model(
25
+ model,
26
+ r = 16, # Choose any number > 0 ! Suggested 8, 16, 32, 64, 128
27
+ target_modules = ["q_proj", "k_proj", "v_proj", "o_proj"] , #"gate_proj", "up_proj", "down_proj",],
28
+ lora_alpha = 16,
29
+ lora_dropout = 0, # Supports any, but = 0 is optimized
30
+ bias = "none", # Supports any, but = "none" is optimized
31
+ # [NEW] "unsloth" uses 30% less VRAM, fits 2x larger batch sizes!
32
+ use_gradient_checkpointing = "unsloth", # True or "unsloth" for very long context
33
+ random_state = 3407,
34
+ use_rslora = False, # We support rank stabilized LoRA
35
+ loftq_config = None, # And LoftQ
36
+ )
37
+
38
+
39
+ from datasets import load_dataset, Dataset
40
+ from unsloth.chat_templates import get_chat_template
41
+ from unsloth.chat_templates import standardize_sharegpt
42
+
43
+ tokenizer = get_chat_template(
44
+ tokenizer,
45
+ chat_template = "qwen-2.5",
46
+ )
47
+
48
+ def formatting_prompts_func(examples):
49
+ convos = examples["conversations"]
50
+ texts = [tokenizer.apply_chat_template(convo, tokenize=False, add_generation_prompt=False) for convo in convos]
51
+ return { "text" : texts, }
52
+
53
+ #dataset = load_dataset("mlabonne/FineTome-100k", split="train")
54
+ traindataset_file = "./dataset_lfs/CN_py800_catmix_5rand_4fold_train_pairs_0.json" #"./dataset_lfs/CN_py800_catmix_5rand_4fold_train_oripairs_sampled.json" # './dataset_lfs/CN_py800_catmix_5rand_4fold_train_full_sampled.json'
55
+ traindata = []
56
+ with open(traindataset_file, 'r') as file:
57
+ for l in file:
58
+ traindata.append(json.loads(l))
59
+
60
+ dataset = Dataset.from_dict({key: [d[key] for d in traindata] for key in traindata[0]})
61
+ print(dataset.column_names)
62
+ valdataset_file = "./llm_for_code/datasets/codecontests/CN_py800_catmix_5rand_val_pairss.json" #CN_py800_catmix_5rand_val_oripairs_sampled.json" #
63
+ valdata = []
64
+ with open(valdataset_file, 'r') as file:
65
+ for l in file:
66
+ valdata.append(json.loads(l))
67
+
68
+ valdataset = Dataset.from_dict({key: [d[key] for d in valdata] for key in valdata[0]})
69
+
70
+ prompt = "Given two programs, check if they both solve the same problem or not i.e. for any given input, would they both give the same output or not. Give the answer as either 'Yes' or 'No'. Explanation is not required \nProgram 1:"
71
+ def create_conversations(example, prompt = prompt):
72
+ if example['label']:
73
+ ans = "Yes"
74
+ else:
75
+ ans = "No"
76
+ prompt_ext = prompt + example['prog1']['scode'] + "\nProgram 2:" + example['prog2']['scode'] + '\n'
77
+ return {
78
+ "conversations": [
79
+
80
+ #{"role": "system", "content": "You are a helpful assistant."}, # Optional system context
81
+ {"role": "user", "content": prompt_ext},
82
+ {"role": "assistant", "content": ans}
83
+ ]
84
+ }
85
+
86
+ dataset = dataset.map(create_conversations)
87
+ dataset = standardize_sharegpt(dataset)
88
+ dataset = dataset.map(formatting_prompts_func, batched=True)
89
+ def format_dataset(example):
90
+ full_text = example["text"] # Full conversation
91
+
92
+ # Ensure assistant part is extracted
93
+ parts = full_text.split("<|im_start|>assistant\n")
94
+
95
+ if len(parts) < 2:
96
+ return None # Skip if there's no assistant response
97
+
98
+ input_text = parts[0] # System + User
99
+ output_text = parts[1].split("<|im_end|>")[0].strip() # Assistant response
100
+
101
+ if not output_text:
102
+ return None # Skip examples with no assistant response
103
+
104
+ # Tokenize input and output separately
105
+ inputs = tokenizer(input_text, padding="max_length", truncation=True, max_length=512)
106
+ labels = tokenizer(output_text, padding="max_length", truncation=True, max_length=512)["input_ids"]
107
+
108
+ # Replace padding token ID with -100 to ignore loss computation on padding
109
+ labels = [(l if l != tokenizer.pad_token_id else -100) for l in labels]
110
+
111
+ # Ensure labels contain real tokens
112
+ if all(l == -100 for l in labels):
113
+ return None # Skip bad examples
114
+
115
+ inputs["labels"] = labels
116
+ return inputs
117
+
118
+ # Apply transformation
119
+ dataset = dataset.map(format_dataset, batched=False, remove_columns=["text"])
120
+
121
+ valdataset = valdataset.map(create_conversations)
122
+ valdataset = standardize_sharegpt(valdataset)
123
+ valdataset = valdataset.map(formatting_prompts_func, batched=True)
124
+
125
+
126
+ valdataset = valdataset.map(format_dataset, batched=False)
127
+
128
+ print(valdataset[0], dataset[0])
129
+ from trl import SFTTrainer
130
+ from transformers import TrainingArguments, DataCollatorForSeq2Seq
131
+ from unsloth import is_bfloat16_supported
132
+ import wandb
133
+ from transformers import TrainingArguments, TrainerCallback
134
+
135
+ wandb.init(project="qwen_training", name="HPC_19_02_25_qwen_CN_py800_per2")
136
+
137
+ class SaveBestModelCallback(TrainerCallback):
138
+ def __init__(self, trainer):
139
+ self.trainer = trainer
140
+ self.best_val_loss = float("inf")
141
+
142
+ def on_evaluate(self, args, state, control, metrics, **kwargs):
143
+ val_loss = metrics.get("eval_loss")
144
+ if val_loss is not None and val_loss < self.best_val_loss:
145
+ self.best_val_loss = val_loss
146
+ print(f" New best model found! Saving at step {state.global_step} (Val Loss: {val_loss:.4f})")
147
+ self.trainer.save_model(f"{args.output_dir}/best_model") # Save best model
148
+
149
+
150
+ from transformers import DataCollatorForSeq2Seq
151
+
152
+ class DebugDataCollator(DataCollatorForSeq2Seq):
153
+ def __call__(self, features):
154
+ batch = super().__call__(features) # Process batch normally
155
+
156
+ # Check if "text" exists, otherwise use decoded input_ids
157
+ raw_text = features[0].get("text", tokenizer.decode(features[0]["input_ids"], skip_special_tokens=False))
158
+ input_ids = batch["input_ids"][0] # Take first sample from batch
159
+ labels = batch["labels"][0] if "labels" in batch else None
160
+
161
+ print("\n🔹 Raw Input Sentence:\n", raw_text)
162
+ print("\n🔹 Raw labels:\n", labels)
163
+ print("\n🔹 Tokenized Input IDs:\n", input_ids)
164
+ print("\n🔹 Decoded Input Sentence:\n", tokenizer.decode(input_ids, skip_special_tokens=False))
165
+
166
+ if labels is not None:
167
+ output_text = tokenizer.decode([t if t != -100 else tokenizer.pad_token_id for t in labels], skip_special_tokens=False)
168
+ print("\n🔹 Tokenized Output IDs:\n", labels)
169
+ print("\n🔹 Decoded Output Sentence:\n", output_text)
170
+
171
+ return batch
172
+
173
+
174
+
175
+ trainer = SFTTrainer(
176
+ model = model,
177
+ tokenizer = tokenizer,
178
+ train_dataset = dataset,
179
+ eval_dataset = valdataset,
180
+ dataset_text_field = "text",
181
+ max_seq_length = max_seq_length,
182
+ data_collator = DataCollatorForSeq2Seq(tokenizer = tokenizer),
183
+ dataset_num_proc = 4,
184
+ packing = False, # Can make training 5x faster for short sequences.
185
+ #data_collator=DebugDataCollator(tokenizer=tokenizer),
186
+ args = TrainingArguments(
187
+ per_device_train_batch_size = 1,
188
+ gradient_accumulation_steps = 4, # Fixed major bug in latest Unsloth
189
+ warmup_steps = 5,
190
+ num_train_epochs = 5, # Set this for 1 full training run.
191
+ #max_steps = 30,
192
+ learning_rate = 2e-4,
193
+ fp16 = not is_bfloat16_supported(),
194
+ bf16 = is_bfloat16_supported(),
195
+ logging_steps = 1000,
196
+ evaluation_strategy="steps", # Evaluate at set intervals
197
+ eval_steps=1000, # Evaluate every 1000 steps
198
+ save_steps=8000, # Save every 5000 steps
199
+ save_total_limit=5,
200
+ load_best_model_at_end=True,
201
+ metric_for_best_model="eval_loss", # Use validation loss
202
+ greater_is_better=False,
203
+ optim = "paged_adamw_8bit", # Save more memory
204
+ weight_decay = 0.01,
205
+ lr_scheduler_type = "linear",
206
+ seed = 3407,
207
+ output_dir = "HPC_19_02_25_qwen_CN_py800_catmix_5rand_perchat_4",
208
+ report_to = "wandb", # Use this for WandB etc
209
+ ),
210
+ )
211
+
212
+
213
+ from transformers import DataCollatorForSeq2Seq
214
+
215
+
216
+
217
+ trainer.add_callback(SaveBestModelCallback(trainer))
218
+
219
+
220
+
221
+ from unsloth.chat_templates import train_on_responses_only
222
+
223
+ # trainer = train_on_responses_only(
224
+ # trainer,
225
+ # instruction_part = "<|im_start|>user\n",
226
+ # response_part = "<|im_start|>assistant\n",
227
+ # )
228
+
229
+
230
+ tokenizer.decode(trainer.train_dataset[5]["input_ids"])
231
+
232
+ space = tokenizer(" ", add_special_tokens = False).input_ids[0]
233
+ tokenizer.decode([space if x == -100 else x for x in trainer.train_dataset[5]["labels"]])
234
+
235
+ #@title Show current memory stats
236
+ gpu_stats = torch.cuda.get_device_properties(0)
237
+ start_gpu_memory = round(torch.cuda.max_memory_reserved() / 1024 / 1024 / 1024, 3)
238
+ max_memory = round(gpu_stats.total_memory / 1024 / 1024 / 1024, 3)
239
+
240
+ print(f"GPU = {gpu_stats.name}. Max memory = {max_memory} GB.")
241
+ print(f"{start_gpu_memory} GB of memory reserved.")
242
+ print(trainer.train_dataset[0].keys())
243
+ trainer.evaluate()
244
+
245
+ trainer_stats = trainer.train()
246
+
247
+ wandb.finish()
248
+
249
+ #@title Show final memory and time stats
250
+ used_memory = round(torch.cuda.max_memory_reserved() / 1024 / 1024 / 1024, 3)
251
+ used_memory_for_lora = round(used_memory - start_gpu_memory, 3)
252
+ used_percentage = round(used_memory /max_memory*100, 3)
253
+ lora_percentage = round(used_memory_for_lora/max_memory*100, 3)
254
+
255
+ print(f"{trainer_stats.metrics['train_runtime']} seconds used for training.")
256
+ print(f"{round(trainer_stats.metrics['train_runtime']/60, 2)} minutes used for training.")
257
+ print(f"Peak reserved memory = {used_memory} GB.")
258
+ print(f"Peak reserved memory for training = {used_memory_for_lora} GB.")
259
+ print(f"Peak reserved memory % of max memory = {used_percentage} %.")
260
+ print(f"Peak reserved memory for training % of max memory = {lora_percentage} %.")
261
+
262
+
263
+
264
+
265
+ from unsloth.chat_templates import get_chat_template
266
+
267
+ tokenizer = get_chat_template(
268
+ tokenizer,
269
+ chat_template = "qwen-2.5",
270
+ )
271
+ FastLanguageModel.for_inference(model) # Enable native 2x faster inference
272
+
273
+ messages = [
274
+ {"role": "user", "content": "Continue the fibonnaci sequence: 1, 1, 2, 3, 5, 8,"},
275
+ ]
276
+ inputs = tokenizer.apply_chat_template(
277
+ messages,
278
+ tokenize = True,
279
+ add_generation_prompt = True, # Must add for generation
280
+ return_tensors = "pt",
281
+ ).to("cuda")
282
+
283
+ outputs = model.generate(input_ids = inputs, max_new_tokens = 64, use_cache = True,
284
+ temperature = 1.5, min_p = 0.1)
285
+ tokenizer.batch_decode(outputs)
286
+
287
+
288
+
289
+ FastLanguageModel.for_inference(model) # Enable native 2x faster inference
290
+
291
+ # messages = [
292
+ # {"role": "user", "content": "Continue the fibonnaci sequence: 1, 1, 2, 3, 5, 8,"},
293
+ # ]
294
+ # inputs = tokenizer.apply_chat_template(
295
+ # messages,
296
+ # tokenize = True,
297
+ # add_generation_prompt = True, # Must add for generation
298
+ # return_tensors = "pt",
299
+ # ).to("cuda")
300
+
301
+ # from transformers import TextStreamer
302
+ # text_streamer = TextStreamer(tokenizer, skip_prompt = True)
303
+ # _ = model.generate(input_ids = inputs, streamer = text_streamer, max_new_tokens = 128, \
304
+ # use_cache = True, temperature = 1.5, min_p = 0.1)
305
+
306
+
307
+
308
+ model.save_pretrained("HPC_19_02_25_qwen_CN_py800_catmix_5rand_perchat_4/unslothlora_model") # Local saving
309
+ tokenizer.save_pretrained("HPC_19_02_25_qwen_CN_py800_catmix_5rand_perchat_4/unslothlora_model")
310
+
311
+ # model.push_to_hub("your_name/lora_model", token = "...") # Online saving
312
+ # tokenizer.push_to_hub("your_name/lora_model", token = "...") # Online saving
313
+
314
+ from unsloth import FastLanguageModel
315
+ from transformers import TextStreamer
316
+
317
+ if False:
318
+ model, tokenizer = FastLanguageModel.from_pretrained(
319
+ model_name="unslothlora_model", # YOUR MODEL YOU USED FOR TRAINING
320
+ max_seq_length=max_seq_length,
321
+ dtype=dtype,
322
+ load_in_4bit=load_in_4bit,
323
+ )
324
+
325
+ FastLanguageModel.for_inference(model)
326
+
327
+ messages = [
328
+ {"role": "user", "content": prompt + "print(hi) \nProgram 2: print(\"hi\")\n"},
329
+ ]
330
+ inputs = tokenizer.apply_chat_template(
331
+ messages,
332
+ tokenize=True,
333
+ add_generation_prompt=True, # Must add for generation
334
+ return_tensors="pt",
335
+ ).to("cuda")
336
+
337
+ text_streamer = TextStreamer(tokenizer, skip_prompt = True)
338
+ _ = model.generate(input_ids=inputs, streamer=text_streamer, max_new_tokens=128, use_cache=True, temperature=1.5, min_p=0.1)
339
+
340
+
341
+
342
+
343
+ # from unsloth import FastLanguageModel
344
+ # from transformers import TextStreamer
345
+
346
+ # if False:
347
+ # new_model, new_tokenizer = FastLanguageModel.from_pretrained(
348
+ # model_name="lora_model", # YOUR MODEL YOU USED FOR TRAINING
349
+ # max_seq_length=max_seq_length,
350
+ # dtype=dtype,
351
+ # load_in_4bit=load_in_4bit,
352
+ # )
353
+ # FastLanguageModel.for_inference(new_model) # Enable native 2x faster inference
354
+
355
+ # messages = [
356
+ # {"role": "user", "content": "Describe a famous statue in New York City."},
357
+ # ]
358
+ # inputs = new_tokenizer.apply_chat_template(
359
+ # messages,
360
+ # tokenize=True,
361
+ # add_generation_prompt=True, # Must add for generation
362
+ # return_tensors="pt",
363
+ # ).to("cuda")
364
+
365
+ # text_streamer = TextStreamer(new_tokenizer, skip_prompt = True)
366
+ # _ = new_model.generate(input_ids=inputs, streamer=text_streamer, max_new_tokens=128, use_cache=True, temperature=1.5, min_p=0.1)