LIFineTuned / app.py
alexkueck's picture
Update app.py
58819fa
#!/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")