#!/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, BitsAndBytesConfig, from sentence_transformers.losses import CosineSimilarityLoss 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) #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=["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 #falls Quanitsation für das training hinzugefügt werden soll (speed up gewählt wird) bnb_config = bnb_config(True, True) # ######################################## #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, #quantization_config=bnb_config, 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, ) ''' ################################################# ''' ################################################# # 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")