Spaces:
Paused
Paused
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| import os | |
| from huggingface_hub import login | |
| import gradio as gr | |
| #from transformers import pipeline | |
| import torch | |
| from utils import * | |
| from presets import * | |
| from transformers import Trainer, TrainingArguments, DataCollatorForLanguageModeling | |
| import numpy as np | |
| import evaluate | |
| import pandas as pd | |
| import sklearn | |
| from sklearn.model_selection import train_test_split | |
| from sklearn.metrics import accuracy_score, recall_score, precision_score, f1_score | |
| import pprint | |
| from peft import ( | |
| prepare_model_for_int8_training, | |
| LoraConfig, | |
| get_peft_model, | |
| get_peft_model_state_dict, | |
| ) | |
| #################################################### | |
| # Konstanten | |
| #################################################### | |
| OUTPUT_DIR = "alexkueck/li-tis-tuned-2" | |
| ''' | |
| #Konstanten speziell für Baize Model: | |
| MICRO_BATCH_SIZE = int(arg2) | |
| BATCH_SIZE = 64 | |
| size = arg1 | |
| GRADIENT_ACCUMULATION_STEPS = BATCH_SIZE // MICRO_BATCH_SIZE | |
| EPOCHS = 1 | |
| LEARNING_RATE = float(arg3) | |
| CUTOFF_LEN = 512 | |
| LORA_R = 8 | |
| LORA_ALPHA = 16 | |
| LORA_DROPOUT = 0.05 | |
| VAL_SET_SIZE = 2000 | |
| TARGET_MODULES = [ | |
| "q_proj", | |
| "k_proj", | |
| "v_proj", | |
| "down_proj", | |
| "gate_proj", | |
| "up_proj", | |
| ] | |
| ''' | |
| ##################################################### | |
| #Hilfsfunktionen für das Training | |
| ##################################################### | |
| #Datensets in den Tokenizer schieben... | |
| def tokenize_function(examples): | |
| return tokenizer(examples["text"], padding="max_length", truncation=True) | |
| #Funktion, die den gegebenen Text aus dem Datenset gruppiert | |
| def group_texts(examples): | |
| # Concatenate all texts. | |
| concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()} | |
| total_length = len(concatenated_examples[list(examples.keys())[0]]) | |
| # We drop the small remainder, we could add padding if the model supported it instead of this drop, you can | |
| # customize this part to your needs. | |
| total_length = (total_length // block_size) * block_size | |
| # Split by chunks of max_len. | |
| result = { | |
| k: [t[i : i + block_size] for i in range(0, total_length, block_size)] | |
| for k, t in concatenated_examples.items() | |
| } | |
| result["labels"] = result["input_ids"].copy() | |
| return result | |
| #Generate Response - nach dem training testen, wie es funktioniert | |
| def generate_response(prompt, model, tokenizer): | |
| input_ids = tokenizer.encode(prompt, return_tensors="pt") | |
| output = model.generate(input_ids, max_length=100) | |
| response = tokenizer.decode(output[:, input_ids.shape[-1]:][0], skip_special_tokens=True) | |
| return response | |
| #Funktion, die der trainer braucht, um das Training zu evaluieren - mit einer Metrik | |
| def compute_metrics(eval_pred): | |
| metric = evaluate.load("glue", "mrpc") | |
| logits, labels = eval_pred | |
| predictions = np.argmax(logits, axis=-1) | |
| #Call compute on metric to calculate the accuracy of your predictions. | |
| #Before passing your predictions to compute, you need to convert the predictions to logits (remember all Transformers models return logits): | |
| return metric.compute(predictions=predictions, references=labels) | |
| #oder mit allen Metriken | |
| def compute_metrics_alle(eval_pred): | |
| metrics = ["accuracy", "recall", "precision", "f1"] #List of metrics to return | |
| metric={} | |
| for met in metrics: | |
| metric[met] = load_metric(met) | |
| logits, labels = eval_pred | |
| predictions = np.argmax(logits, axis=-1) | |
| metric_res={} | |
| for met in metrics: | |
| metric_res[met]=metric[met].compute(predictions=predictions, references=labels)[met] | |
| return metric_res | |
| ################################################################################### | |
| ################################################################################### | |
| #Access-Token (in Secrets) | |
| #aus den Secrets importieren (siehe Setting zu diesem Space) | |
| login(token=os.environ["HF_ACCESS_TOKEN"]) #for read access!!!! | |
| #################################################################################### | |
| #Modelle und Tokenizer | |
| #Alternativ mit beliebigen Modellen: | |
| #base_model = "project-baize/baize-v2-7b" #load_8bit = True (in load_tokenizer_and_model) | |
| #base_model = "TheBloke/airoboros-13B-HF" #load_8bit = False (in load_tokenizer_and_model) | |
| base_model = "EleutherAI/gpt-neo-1.3B" #load_8bit = False (in load_tokenizer_and_model) | |
| #base_model = "TheBloke/airoboros-13B-HF" #load_8bit = True | |
| #base_model = "TheBloke/vicuna-13B-1.1-HF" #load_8bit = ? | |
| #base_model="gpt2-xl" | |
| # Load model directly | |
| ##################################################### | |
| #Tokenizer und Model laden | |
| tokenizer,model,device = load_tokenizer_and_model(base_model, False) | |
| ################################################# | |
| # Few-Shot Training!!!!!!!!! | |
| ################################################# | |
| # Load SetFit model from Hub | |
| #tokenizer,model,device = load_tokenizer_and_model_setFit(base_model, False) | |
| #tokenizer.add_special_tokens({'pad_token': '[PAD]'}) #not necessary with fast Toekenizers like GPT2 | |
| ''' | |
| #für Baize.... da spezieller Tokenizer geladen werden muss... | |
| # hier werden aber Chat-Daten geladen!!!! | |
| tokenizer,model,device = load_tokenizer_and_model_Baize(base_model, True) | |
| config = LoraConfig( | |
| r=8, | |
| lora_alpha=16, | |
| target_modules=TARGET_MODULES, | |
| lora_dropout=0.05, | |
| bias="none", | |
| task_type="CAUSAL_LM", | |
| ) | |
| config.save_pretrained(OUTPUT_DIR) | |
| model = get_peft_model(model, config) | |
| #da schneller Tokenizer-> Attention Mask setzen | |
| tokenizer.pad_token_id = 0 | |
| ''' | |
| #################################################### | |
| #Datensets für Finetuning laden | |
| dataset_neu = daten_laden("alexkueck/tis") | |
| #dataset_neu = daten_laden("EleutherAI/pile") | |
| #dataset_neu = daten_laden("yelp_review_full") | |
| ############################################# | |
| #Vorbereiten für das Training der neuen Daten | |
| ############################################# | |
| print ("################################") | |
| print("Datenset vorbereiten") | |
| #alles zusammen auf das neue datenset anwenden - batched = True und 4 Prozesse, um die Berechnung zu beschleunigen. Die "text" - Spalte braucht man anschließend nicht mehr, daher weglassen. | |
| tokenized_datasets = dataset_neu.map(tokenize_function, batched=True, num_proc=4, remove_columns=["text","label"]) #, remove_columns=["id","text"]) | |
| #wenn man zum Trainieren erstmal nur einen kleinen Datensatz nehem möchte: | |
| #small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000)) | |
| #small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000)) | |
| #Probe ansehen - zum überprüfen... | |
| print('##################Beispiel Datensatz ################') | |
| print (tokenized_datasets["train"][4]) | |
| print (tokenizer.decode(tokenized_datasets["train"][4]["input_ids"])) | |
| #den Text nun zusammenführen (concatenieren) und anschließend in kleine Häppchen aufteilen (block_size=128), die verarbeitet werden können | |
| #das macht die map-Funktion und das Attribut batched = True | |
| #man könnte das weglassen, wenn jeder Satz einzeln gegeben wurde in den Texten... | |
| #eigentlich nimmt man als block_size die max. Länge in der das Model trainiert wurde -> könnte aber zu groß sein für den RAm der GPU , daher hier 128 gewählt | |
| # block_size = tokenizer.model_max_length | |
| block_size = 128 | |
| #nochmal die map-Funktion auf das bereits tokenisierte Datenset anwenden | |
| #die bereits tokenisierten Datensatze ändern sich dadurch: die samples enthalten nun Mengen aus block_size Tokens | |
| #lm_datasets = tokenized_datasets.map(group_texts, batched=True, batch_size=1000, num_proc=4,) | |
| lm_datasets = tokenized_datasets | |
| # Batches von Daten zusammenfassen | |
| data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False) | |
| print ("###############lm datasets####################") | |
| #print (tokenizer.decode(lm_datasets["train"][1]["input_ids"])) | |
| #die Daten wurden nun "gereinigt" und für das Model vorbereitet. | |
| #z.B. anschauen mit: tokenizer.decode(lm_datasets["train"][1]["input_ids"]) | |
| #################################################### | |
| #Training | |
| #################################################### | |
| print ("################################") | |
| print ("training args") | |
| #Training Args | |
| batch_size = 2 | |
| # ######################################## | |
| #Training Argumente setzen (kleinere LLMs) | |
| training_args = TrainingArguments( | |
| output_dir="alexkueck/li-tis-tuned-2", | |
| overwrite_output_dir = 'True', | |
| per_device_train_batch_size=batch_size, #batch_size = 2 for full training | |
| per_device_eval_batch_size=batch_size, | |
| num_train_epochs=5, | |
| logging_steps=5000, | |
| evaluation_strategy = "epoch", #oder steps | |
| logging_strategy="epoch", #oder steps | |
| #logging_steps=10, | |
| logging_dir='logs', | |
| learning_rate= 2e-5, #4e-05, | |
| #weight_decay=0.01, | |
| save_total_limit = 2, | |
| #predict_with_generate=True, | |
| #logging_steps=2, # set to 1000 for full training | |
| #save_steps=16, # set to 500 for full training | |
| #eval_steps=4, # set to 8000 for full training | |
| warmup_steps = 1, # set to 2000 for full training | |
| #max_steps=16, # delete for full training | |
| # overwrite_output_dir=True, | |
| #save_total_limit=1, | |
| #fp16=True, | |
| save_strategy = "no", | |
| optim="adamw_torch", | |
| #load_best_model_at_end=False, | |
| #load_best_model_at_end=True | |
| #push_to_hub=True, | |
| ) | |
| #Trainer zusammenstellen | |
| print ("################################") | |
| print ("trainer") | |
| trainer = Trainer( | |
| model=model, | |
| args=training_args, | |
| train_dataset=lm_datasets["train"], | |
| eval_dataset=lm_datasets["test"], | |
| #train_dataset=small_train_dataset, | |
| #eval_dataset=small_eval_dataset, | |
| data_collator=data_collator, | |
| tokenizer=tokenizer, | |
| compute_metrics=compute_metrics, | |
| ) | |
| ############################################### | |
| # Special QA Trainer...# | |
| ''' | |
| trainer = QuestionAnsweringTrainer( | |
| model=model, | |
| args=training_args, | |
| train_dataset=train_dataset if training_args.do_train else None, | |
| eval_dataset=eval_dataset if training_args.do_eval else None, | |
| eval_examples=eval_examples if training_args.do_eval else None, | |
| tokenizer=tokenizer, | |
| data_collator=data_collator, | |
| post_process_function=post_processing_function, | |
| compute_metrics=compute_metrics, | |
| ) | |
| ''' | |
| ################################################# | |
| ''' | |
| ################################################# | |
| # Few-Shot Training!!!!!!!!! | |
| ################################################# | |
| # Create Few-Shot trainer | |
| trainer = SetFitTrainer( | |
| model=model, | |
| train_dataset=train_ds, | |
| eval_dataset=test_ds, | |
| loss_class=CosineSimilarityLoss, | |
| batch_size=16, | |
| num_iterations=20, # Number of text pairs to generate for contrastive learning | |
| num_epochs=1 # Number of epochs to use for contrastive learning | |
| ) | |
| ################################################# | |
| # special Trainer Baize Model | |
| # Parameters für Model 7b: 7b 32 0.0002 | |
| # Model 13b: 13b 16 0.0001 | |
| # Model 30b: 30b 8 0.00005 | |
| arg1 = '7b' | |
| arg2 = 32 | |
| arg3 = 0.0002 | |
| device_map = "auto" | |
| world_size = int(os.environ.get("WORLD_SIZE", 1)) | |
| ddp = world_size != 1 | |
| if ddp: | |
| device_map = {"": int(os.environ.get("LOCAL_RANK") or 0)} | |
| GRADIENT_ACCUMULATION_STEPS = GRADIENT_ACCUMULATION_STEPS // world_size | |
| trainer = transformers.Trainer( | |
| model=model, | |
| train_dataset=lm_datasets["train"], | |
| eval_dataset=lm_datasets["test"], | |
| args=transformers.TrainingArguments( | |
| output_dir="alexkueck/li-tis-tuned-2", | |
| overwrite_output_dir = 'True', | |
| per_device_train_batch_size=MICRO_BATCH_SIZE, | |
| per_device_eval_batch_size=MICRO_BATCH_SIZE, | |
| gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS, | |
| warmup_steps=100, | |
| num_train_epochs=EPOCHS, | |
| learning_rate=LEARNING_RATE, | |
| fp16=True, | |
| logging_steps=20, | |
| evaluation_strategy="steps" if VAL_SET_SIZE > 0 else "no", | |
| save_strategy="steps", | |
| eval_steps=200 if VAL_SET_SIZE > 0 else None, | |
| save_steps=200, | |
| save_total_limit=100, | |
| load_best_model_at_end=True if VAL_SET_SIZE > 0 else False, | |
| ddp_find_unused_parameters=False if ddp else None, | |
| ), | |
| data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False), | |
| ) | |
| model.config.use_cache = False | |
| ''' | |
| #trainer ausführen | |
| trainer.train() | |
| #Wenn man vom letzten checkpoint aus weiter trainieren möchte: trainer.train(resume_from_checkpoint=True) | |
| print ("################################") | |
| print("trained!!!!!") | |
| ################## | |
| #Evaluate the new Model auf evual dataset | |
| #loss: Gesamt-Verlust die das Modell auf den Test-Daten liefert (möglichst niedrig) | |
| #accuracy: Wie genau die Vorhersage des neuen Modelss auf den Test Daten funktioniert (möglichst nahe 1) | |
| #f1_score: Maß für Genauigkeit des Modells ? (möglichst nahe 1) | |
| #recall: Recall ist ein Maß dafür, wie viele der tatsächlich positiven Beispiele das Modell richtig klassifiziert hat (möglichst nahe 1) | |
| #precision: Maß dafür, wie viele der vom Modell als positiv klassifizierten Beispiele tatsächlich positiv sind (möglichst nahe 1) | |
| print ("#################Evaluate:#################") | |
| results = trainer.evaluate(eval_dataset=lm_datasets["test"]) | |
| # Ausgabe der Ergebnisse | |
| for key, value in results.items(): | |
| print(key, value) | |
| print("Done Eval") | |
| print('################ Test Trained Model ###################') | |
| predictions = trainer.predict(lm_datasets["test"]) | |
| preds = np.argmax(predictions.predictions, axis=-1) | |
| print('###########preds##################') | |
| print(preds) | |
| ################################################### | |
| #Save to a place -????? Where???? | |
| #print("Save to ???") | |
| #login(token=os.environ["HF_WRITE_TOKEN"]) | |
| #trainer.save_model("alexkueck/li-tis-tuned-1") | |
| #print("done") | |
| ##################################### | |
| #Push to Hub | |
| print ("################################") | |
| print("###################push to hub###################") | |
| print("push to hub - Model") | |
| login(token=os.environ["HF_WRITE_TOKEN"]) | |
| trainer.push_to_hub("alexkueck/li-tis-tuned-2") | |
| print("push to hub - Tokenizer") | |
| tokenizer.push_to_hub("alexkueck/li-tis-tuned-2") | |
| print("Fertig mit Push to Hub") | |