crittiksglobal commited on
Commit
becd09b
·
verified ·
1 Parent(s): 95c8999

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +11 -539
app.py CHANGED
@@ -1,549 +1,21 @@
1
  import gradio as gr
2
  import torch
3
- import json
4
- import time
5
  import os
6
 
7
- # Ensure Gradio cache directory exists
8
  os.makedirs("/tmp/gradio", exist_ok=True)
9
- os.environ["GRADIO_TEMP_DIR"] = "/tmp/gradio"
10
 
11
- # Dataset configs - verified PUBLIC datasets
12
- DATASETS = {
13
- "NousResearch Hermes": {
14
- "name": "NousResearch/hermes-function-calling-v1",
15
- "type": "tool_calling"
16
- },
17
- "Glaive Code Assistant": {
18
- "name": "glaiveai/glaive-code-assistant-v2",
19
- "type": "tool_calling"
20
- },
21
- "OpenAssistant": {
22
- "name": "OpenAssistant/oasst1",
23
- "type": "chat"
24
- },
25
- "Custom Upload": {
26
- "name": "custom",
27
- "type": "custom"
28
- }
29
- }
30
 
31
- # Model configs - organized by size
32
- MODELS = {
33
- # Tiny (< 1B) - Fast training
34
- "Qwen2.5-0.5B-Instruct": "Qwen/Qwen2.5-0.5B-Instruct",
35
- "SmolLM2-360M": "HuggingFaceTB/SmolLM2-360M-Instruct",
36
 
37
- # Small (1-2B) - Good balance
38
- "Qwen2.5-1.5B-Instruct": "Qwen/Qwen2.5-1.5B-Instruct",
39
- "TinyLlama-1.1B": "TinyLlama/TinyLlama-1.1B-Chat-v1.0",
40
- "Gemma-2-2B": "google/gemma-2-2b-it",
41
- "SmolLM2-1.7B": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
42
- "Llama-3.2-1B": "meta-llama/Llama-3.2-1B-Instruct",
43
 
44
- # Medium (3-4B) - More capable
45
- "Qwen2.5-3B-Instruct": "Qwen/Qwen2.5-3B-Instruct",
46
- "Llama-3.2-3B": "meta-llama/Llama-3.2-3B-Instruct",
47
- "Phi-3.5-mini": "microsoft/Phi-3.5-mini-instruct",
48
 
49
- # Large (7B+) - Most capable (slower)
50
- "Qwen2.5-7B-Instruct": "Qwen/Qwen2.5-7B-Instruct",
51
- "Mistral-7B-v0.3": "mistralai/Mistral-7B-Instruct-v0.3",
52
- "Gemma-2-9B": "google/gemma-2-9b-it",
53
- }
54
-
55
- def format_example(example, dataset_type):
56
- """Format dataset examples for training"""
57
- if dataset_type == "tool_calling":
58
- if "conversations" in example:
59
- convs = example["conversations"]
60
- if isinstance(convs, list):
61
- text = ""
62
- for conv in convs:
63
- role = conv.get("from", conv.get("role", "user"))
64
- content = conv.get("value", conv.get("content", ""))
65
- if role in ["system", "gpt", "assistant"]:
66
- role_tag = "assistant" if role in ["gpt", "assistant"] else "system"
67
- else:
68
- role_tag = "user"
69
- text += f"<|im_start|>{role_tag}\n{content}\n<|im_end|>\n"
70
- return text
71
-
72
- query = example.get("question", example.get("instruction", example.get("query", "")))
73
- response = example.get("response", example.get("answer", example.get("output", "")))
74
- return f"<|im_start|>user\n{query}\n<|im_end|>\n<|im_start|>assistant\n{response}\n<|im_end|>"
75
-
76
- elif dataset_type == "chat":
77
- if "messages" in example:
78
- text = ""
79
- for msg in example["messages"]:
80
- role = msg.get("role", "user")
81
- content = msg.get("content", msg.get("text", ""))
82
- text += f"<|im_start|>{role}\n{content}\n<|im_end|>\n"
83
- return text
84
- return str(example)
85
-
86
- elif dataset_type == "custom":
87
- if "text" in example:
88
- return example["text"]
89
- elif "messages" in example:
90
- text = ""
91
- for msg in example["messages"]:
92
- role = msg.get("role", "user")
93
- content = msg.get("content", "")
94
- text += f"<|im_start|>{role}\n{content}\n<|im_end|>\n"
95
- return text
96
- elif "instruction" in example:
97
- instr = example.get("instruction", "")
98
- inp = example.get("input", "")
99
- out = example.get("output", "")
100
- prompt = f"{instr}\n{inp}".strip()
101
- return f"<|im_start|>user\n{prompt}\n<|im_end|>\n<|im_start|>assistant\n{out}\n<|im_end|>"
102
- return str(example)
103
-
104
- return str(example)
105
-
106
- def load_custom_dataset(file_path):
107
- """Load custom dataset from uploaded file - supports json, jsonl, csv, parquet, txt"""
108
- data = []
109
- ext = file_path.lower().split('.')[-1] if '.' in file_path else ''
110
-
111
- try:
112
- # Parquet
113
- if ext == 'parquet':
114
- import pandas as pd
115
- df = pd.read_parquet(file_path)
116
- data = df.to_dict('records')
117
-
118
- # CSV
119
- elif ext == 'csv':
120
- import pandas as pd
121
- df = pd.read_csv(file_path)
122
- data = df.to_dict('records')
123
-
124
- # Text file (one example per line)
125
- elif ext == 'txt':
126
- with open(file_path, 'r', encoding='utf-8') as f:
127
- for line in f:
128
- line = line.strip()
129
- if line:
130
- data.append({"text": line})
131
-
132
- # JSON/JSONL
133
- else:
134
- with open(file_path, 'r', encoding='utf-8') as f:
135
- content = f.read().strip()
136
- if content.startswith('{'):
137
- # JSONL format
138
- for line in content.split('\n'):
139
- line = line.strip()
140
- if line:
141
- try:
142
- data.append(json.loads(line))
143
- except:
144
- pass
145
- elif content.startswith('['):
146
- # JSON array
147
- data = json.loads(content)
148
-
149
- except Exception as e:
150
- print(f"Error loading custom dataset: {e}")
151
-
152
- return data
153
-
154
- def train_model(model_name, datasets, max_samples, lora_r, lora_alpha, epochs, output_name, custom_file, continue_training, continue_from, progress=gr.Progress()):
155
- """Train model with LoRA"""
156
-
157
- logs = []
158
- def log(msg):
159
- logs.append(f"[{time.strftime('%H:%M:%S')}] {msg}")
160
- return "\n".join(logs)
161
-
162
- try:
163
- yield log("Checking training libraries...")
164
-
165
- from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, BitsAndBytesConfig, Trainer, DataCollatorForLanguageModeling
166
- from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, PeftModel
167
- from datasets import load_dataset, Dataset
168
-
169
- hf_token = os.environ.get("HF_TOKEN")
170
-
171
- # Determine base model
172
- if continue_training and continue_from:
173
- yield log(f"Continuing training from: {continue_from}")
174
- # Load adapter config to find base model
175
- try:
176
- from huggingface_hub import hf_hub_download
177
- import json as json_lib
178
-
179
- config_path = hf_hub_download(
180
- repo_id=continue_from,
181
- filename="adapter_config.json",
182
- token=hf_token
183
- )
184
- with open(config_path) as f:
185
- adapter_config = json_lib.load(f)
186
- model_id = adapter_config.get("base_model_name_or_path", MODELS.get(model_name, model_name))
187
- yield log(f"Base model: {model_id}")
188
- except Exception as e:
189
- yield log(f"Could not load adapter config: {e}")
190
- model_id = MODELS.get(model_name, model_name)
191
- else:
192
- model_id = MODELS.get(model_name, model_name)
193
-
194
- yield log(f"Loading model: {model_id}")
195
-
196
- bnb_config = BitsAndBytesConfig(
197
- load_in_4bit=True,
198
- bnb_4bit_quant_type="nf4",
199
- bnb_4bit_compute_dtype=torch.bfloat16,
200
- bnb_4bit_use_double_quant=True
201
- )
202
-
203
- tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
204
- if tokenizer.pad_token is None:
205
- tokenizer.pad_token = tokenizer.eos_token
206
-
207
- model = AutoModelForCausalLM.from_pretrained(
208
- model_id,
209
- quantization_config=bnb_config,
210
- device_map="auto",
211
- trust_remote_code=True
212
- )
213
-
214
- yield log(f"Model loaded on {next(model.parameters()).device}")
215
-
216
- # Apply LoRA or load existing adapter
217
- if continue_training and continue_from:
218
- yield log(f"Loading existing LoRA adapter from {continue_from}...")
219
- try:
220
- model = PeftModel.from_pretrained(
221
- model,
222
- continue_from,
223
- is_trainable=True,
224
- token=hf_token
225
- )
226
- yield log("Existing adapter loaded - continuing training!")
227
- except Exception as e:
228
- yield log(f"Could not load adapter: {e}")
229
- yield log("Starting fresh with new LoRA...")
230
- model = prepare_model_for_kbit_training(model)
231
- lora_config = LoraConfig(
232
- r=int(lora_r),
233
- lora_alpha=int(lora_alpha),
234
- target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
235
- lora_dropout=0.05,
236
- bias="none",
237
- task_type="CAUSAL_LM"
238
- )
239
- model = get_peft_model(model, lora_config)
240
- else:
241
- yield log(f"Applying new LoRA (r={lora_r}, alpha={lora_alpha})")
242
- model = prepare_model_for_kbit_training(model)
243
- lora_config = LoraConfig(
244
- r=int(lora_r),
245
- lora_alpha=int(lora_alpha),
246
- target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
247
- lora_dropout=0.05,
248
- bias="none",
249
- task_type="CAUSAL_LM"
250
- )
251
- model = get_peft_model(model, lora_config)
252
-
253
- trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
254
- total = sum(p.numel() for p in model.parameters())
255
- yield log(f"Trainable: {trainable:,} / {total:,} ({100*trainable/total:.2f}%)")
256
-
257
- yield log(f"Loading datasets: {datasets}")
258
-
259
- all_texts = []
260
- samples_per_dataset = max_samples // max(len(datasets), 1)
261
-
262
- for ds_name in datasets:
263
- if ds_name == "Custom Upload":
264
- if custom_file is not None:
265
- yield log("Loading custom dataset...")
266
- try:
267
- custom_data = load_custom_dataset(custom_file)
268
- if custom_data:
269
- for example in custom_data[:samples_per_dataset]:
270
- text = format_example(example, "custom")
271
- all_texts.append(text)
272
- yield log(f"Loaded {min(len(custom_data), samples_per_dataset)} samples from custom dataset")
273
- except Exception as e:
274
- yield log(f"Error: {e}")
275
- continue
276
-
277
- if ds_name not in DATASETS:
278
- yield log(f"Unknown dataset: {ds_name}")
279
- continue
280
-
281
- ds_config = DATASETS[ds_name]
282
- yield log(f"Loading {ds_name}...")
283
-
284
- try:
285
- ds = load_dataset(ds_config["name"], split="train", trust_remote_code=True)
286
- sample_size = min(samples_per_dataset, len(ds))
287
- ds = ds.shuffle(seed=42).select(range(sample_size))
288
-
289
- for example in ds:
290
- text = format_example(example, ds_config["type"])
291
- all_texts.append(text)
292
-
293
- yield log(f"Loaded {sample_size} samples from {ds_name}")
294
-
295
- except Exception as e:
296
- yield log(f"Error loading {ds_name}: {e}")
297
-
298
- if not all_texts:
299
- yield log("ERROR: No data loaded!")
300
- return
301
-
302
- yield log(f"Total training samples: {len(all_texts)}")
303
-
304
- # Tokenize
305
- yield log("Tokenizing dataset...")
306
-
307
- tokenized = tokenizer(all_texts, truncation=True, max_length=512, padding=True)
308
- train_dataset = Dataset.from_dict({
309
- "input_ids": tokenized["input_ids"],
310
- "attention_mask": tokenized["attention_mask"],
311
- "labels": tokenized["input_ids"].copy()
312
- })
313
-
314
- yield log("Setting up trainer...")
315
-
316
- training_args = TrainingArguments(
317
- output_dir=f"./outputs/{output_name}",
318
- num_train_epochs=int(epochs),
319
- per_device_train_batch_size=1,
320
- gradient_accumulation_steps=4,
321
- learning_rate=2e-4,
322
- warmup_ratio=0.03,
323
- logging_steps=10,
324
- save_strategy="epoch",
325
- fp16=True,
326
- optim="paged_adamw_8bit",
327
- report_to="none",
328
- remove_unused_columns=False
329
- )
330
-
331
- data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
332
-
333
- trainer = Trainer(
334
- model=model,
335
- args=training_args,
336
- train_dataset=train_dataset,
337
- data_collator=data_collator
338
- )
339
-
340
- yield log("Starting training...")
341
-
342
- trainer.train()
343
-
344
- yield log("Training complete!")
345
- yield log(f"Saving model to ./outputs/{output_name}")
346
-
347
- trainer.save_model(f"./outputs/{output_name}")
348
- tokenizer.save_pretrained(f"./outputs/{output_name}")
349
-
350
- # Push to HuggingFace Hub
351
- yield log("Pushing to HuggingFace Hub...")
352
- try:
353
- from huggingface_hub import HfApi, create_repo, login
354
-
355
- if hf_token:
356
- login(token=hf_token)
357
-
358
- repo_id = f"crittiksglobal/{output_name}"
359
-
360
- try:
361
- create_repo(repo_id, repo_type="model", exist_ok=True, token=hf_token)
362
- except:
363
- pass
364
-
365
- api = HfApi(token=hf_token)
366
- api.upload_folder(
367
- folder_path=f"./outputs/{output_name}",
368
- repo_id=repo_id,
369
- repo_type="model"
370
- )
371
-
372
- yield log(f"Model pushed to: https://huggingface.co/{repo_id}")
373
- yield log("You can download from there!")
374
-
375
- except Exception as e:
376
- yield log(f"Push failed: {e}")
377
-
378
- yield log("\n=== Training Complete ===")
379
- yield log(f"Base model: {model_id}")
380
- yield log(f"Samples: {len(all_texts)}")
381
- yield log(f"LoRA rank: {lora_r}")
382
- if continue_training:
383
- yield log(f"Continued from: {continue_from}")
384
- yield log(f"Download: https://huggingface.co/crittiksglobal/{output_name}")
385
-
386
- except Exception as e:
387
- import traceback
388
- yield log(f"ERROR: {e}\n{traceback.format_exc()}")
389
-
390
- def test_model(prompt, output_name):
391
- """Test a trained model"""
392
- try:
393
- from transformers import AutoModelForCausalLM, AutoTokenizer
394
- from peft import PeftModel
395
-
396
- hf_token = os.environ.get("HF_TOKEN")
397
-
398
- # Try local first, then Hub
399
- model_path = f"./outputs/{output_name}"
400
- if not os.path.exists(model_path):
401
- model_path = f"crittiksglobal/{output_name}"
402
-
403
- tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True, token=hf_token)
404
- model = AutoModelForCausalLM.from_pretrained(
405
- model_path,
406
- device_map="auto",
407
- torch_dtype=torch.float16,
408
- trust_remote_code=True,
409
- token=hf_token
410
- )
411
-
412
- formatted = f"<|im_start|>user\n{prompt}\n<|im_end|>\n<|im_start|>assistant\n"
413
- inputs = tokenizer(formatted, return_tensors="pt").to(model.device)
414
-
415
- with torch.no_grad():
416
- outputs = model.generate(
417
- **inputs,
418
- max_new_tokens=256,
419
- temperature=0.7,
420
- do_sample=True,
421
- pad_token_id=tokenizer.pad_token_id
422
- )
423
-
424
- response = tokenizer.decode(outputs[0], skip_special_tokens=False)
425
-
426
- if "<|im_start|>assistant" in response:
427
- response = response.split("<|im_start|>assistant")[-1]
428
- if "<|im_end|>" in response:
429
- response = response.split("<|im_end|>")[0]
430
-
431
- return response.strip()
432
-
433
- except Exception as e:
434
- return f"Error: {e}"
435
-
436
- # Gradio UI
437
- with gr.Blocks(title="VertexElite AI Tool Trainer", theme=gr.themes.Soft()) as demo:
438
- gr.Markdown("""
439
- # VertexElite AI Tool Trainer
440
-
441
- Fine-tune **tool-calling** models on ZeroGPU (A10G) with LoRA.
442
- """)
443
-
444
- with gr.Tabs():
445
- with gr.TabItem("Train"):
446
- with gr.Row():
447
- with gr.Column():
448
- model = gr.Dropdown(
449
- choices=list(MODELS.keys()),
450
- value="Qwen2.5-0.5B-Instruct",
451
- label="Base Model"
452
- )
453
-
454
- gr.Markdown("### Continue Training")
455
- continue_training = gr.Checkbox(
456
- label="Continue from existing model",
457
- value=False
458
- )
459
- continue_from = gr.Textbox(
460
- label="Model to continue from",
461
- value="crittiksglobal/vertexelite-v1",
462
- placeholder="crittiksglobal/vertexelite-v1"
463
- )
464
-
465
- gr.Markdown("### Datasets")
466
- dataset = gr.CheckboxGroup(
467
- choices=list(DATASETS.keys()),
468
- value=["Custom Upload"],
469
- label="Select Datasets"
470
- )
471
-
472
- custom_file = gr.File(
473
- label="Upload dataset (jsonl, json, csv, parquet, txt)",
474
- file_types=[".jsonl", ".json", ".csv", ".parquet", ".txt"],
475
- type="filepath"
476
- )
477
-
478
- samples = gr.Slider(100, 5000, 1000, step=100, label="Max Samples")
479
-
480
- with gr.Row():
481
- lora_r = gr.Slider(4, 64, 16, step=4, label="LoRA Rank")
482
- lora_alpha = gr.Slider(8, 128, 32, step=8, label="LoRA Alpha")
483
-
484
- epochs = gr.Slider(1, 3, 1, step=1, label="Epochs")
485
- output = gr.Textbox(value="vertexelite-v1", label="Output Name")
486
-
487
- train_btn = gr.Button("Start Training", variant="primary", size="lg")
488
-
489
- with gr.Column():
490
- logs = gr.Textbox(label="Training Logs", lines=25)
491
-
492
- train_btn.click(
493
- train_model,
494
- [model, dataset, samples, lora_r, lora_alpha, epochs, output, custom_file, continue_training, continue_from],
495
- logs
496
- )
497
-
498
- with gr.TabItem("Test"):
499
- gr.Markdown("Test your trained model")
500
- with gr.Row():
501
- with gr.Column():
502
- test_model_name = gr.Textbox(value="vertexelite-v1", label="Model Name")
503
- prompt = gr.Textbox(label="Prompt", value="Hello, how can you help me?", lines=3)
504
- test_btn = gr.Button("Generate", variant="primary")
505
- with gr.Column():
506
- result = gr.Textbox(label="Output", lines=10)
507
-
508
- test_btn.click(test_model, [prompt, test_model_name], result)
509
-
510
- with gr.TabItem("Info"):
511
- gr.Markdown("""
512
- ### Continue Training
513
-
514
- Check **"Continue from existing model"** to improve an existing model:
515
- 1. Enter the model repo (e.g., `crittiksglobal/vertexelite-v1`)
516
- 2. Upload new training data
517
- 3. Train - it will learn from new data while keeping old knowledge!
518
-
519
- ### Datasets
520
- | Dataset | Description |
521
- |---------|-------------|
522
- | NousResearch Hermes | Function calling |
523
- | Glaive Code Assistant | Code generation |
524
- | OpenAssistant | General chat |
525
- | Custom Upload | Your JSONL/JSON |
526
-
527
- ### Supported Formats
528
- | Format | Description |
529
- |--------|-------------|
530
- | `.jsonl` | One JSON object per line |
531
- | `.json` | Array of objects |
532
- | `.csv` | Columns: instruction, output (or text) |
533
- | `.parquet` | Same columns as CSV |
534
- | `.txt` | One example per line |
535
-
536
- ### Data Format
537
- ```json
538
- {"instruction": "...", "output": "..."}
539
- {"messages": [{"role": "user", "content": "..."}, {"role": "assistant", "content": "..."}]}
540
- {"text": "full conversation text"}
541
- ```
542
-
543
- ### Tips
544
- - Continue training = model gets smarter over time
545
- - Use same output name to update the model
546
- - More data + more epochs = better model
547
- """)
548
-
549
- demo.launch(ssr_mode=False)
 
1
  import gradio as gr
2
  import torch
 
 
3
  import os
4
 
 
5
  os.makedirs("/tmp/gradio", exist_ok=True)
 
6
 
7
+ def test_gpu():
8
+ if torch.cuda.is_available():
9
+ return f"GPU: {torch.cuda.get_device_name(0)}\nVRAM: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB"
10
+ return "No GPU found"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ with gr.Blocks(title="VertexElite AI") as demo:
13
+ gr.Markdown("# VertexElite AI Tool Trainer")
14
+ gr.Markdown("Testing T4 GPU...")
 
 
15
 
16
+ btn = gr.Button("Check GPU")
17
+ output = gr.Textbox(label="GPU Info")
 
 
 
 
18
 
19
+ btn.click(test_gpu, outputs=output)
 
 
 
20
 
21
+ demo.launch()