File size: 13,582 Bytes
91feea3
4e0a704
91feea3
d5b15a3
60d30cc
91feea3
 
 
 
 
70c751a
2513b18
ae63b0f
 
03f2529
 
 
 
de47c46
ca91fc3
 
 
 
 
 
 
3a0bedd
3be2136
 
 
 
456a3d3
 
 
3be2136
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456a3d3
50b8512
ada63db
50b8512
 
 
2aa5ff2
50b8512
ada63db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50b8512
a748911
d38b680
a748911
 
 
 
50b8512
3cf5a13
 
6947b76
3cf5a13
 
 
 
 
0e34887
6947b76
 
378e7cb
 
 
 
 
 
 
 
 
 
 
ca8a270
378e7cb
181494a
0e34887
cc3b6f3
 
37c4d2f
115c7e5
03d727b
3be2136
 
91feea3
cc37d8c
91feea3
764dfa4
91feea3
764dfa4
 
d569d83
de47c46
66627bf
7fe6015
749ec8a
66627bf
c856a9e
4128faf
6a058ad
58819fa
5973677
 
764dfa4
3be2136
87bd6bc
3be2136
ca91fc3
 
 
 
 
 
 
 
a8dcedf
ca91fc3
3be2136
ca91fc3
764dfa4
ca91fc3
 
c856a9e
4128faf
b1a0b6c
39108ff
b1a0b6c
181494a
72b1673
 
 
c95c225
 
f0c1854
181494a
7cdb1c4
181494a
ae63b0f
2e91302
 
ae63b0f
d7d2637
398c906
9acbf52
3f1c59e
ae63b0f
181494a
 
 
 
 
 
 
72b1673
 
2847d97
2e91302
6947b76
ebeb5fd
8acd9a0
6947b76
 
 
8acd9a0
72b1673
 
 
3cf5a13
 
72b1673
 
 
c95c225
d7d2637
72b1673
ba2d3ab
 
2868cef
 
 
764dfa4
3be2136
 
72b1673
cdddabb
7ddeab6
252f8d4
 
6947b76
 
d7d2637
 
 
25c40b4
7dab25d
 
d500f0f
77ee5c9
252f8d4
 
 
7dab25d
252f8d4
 
 
2868cef
6947b76
1b85a4d
d4e216c
f9cf14e
a6ca5ee
72b1673
d7d2637
6947b76
 
95d0743
c95c225
d7d2637
f0c1854
95d0743
72b1673
 
2e91302
 
 
 
8acd9a0
ee00be9
3cf5a13
95d0743
f0c1854
d7d2637
 
3be2136
d7d2637
 
 
 
 
 
 
 
 
 
 
 
 
 
6a058ad
5973677
 
6a058ad
d663d84
 
d329db5
 
 
 
 
 
 
be71153
 
 
 
 
 
 
d663d84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
764dfa4
d663d84
 
d7d2637
95d0743
c646bbc
252f8d4
c95c225
dde4e83
cbcdf0d
d8a47fd
deb4c1f
b6fc2f9
3188026
 
 
 
 
c56cd68
7094d26
 
 
 
deb4c1f
dde4e83
6947b76
c56cd68
 
 
 
6947b76
 
d38b680
 
51fd03b
 
 
 
d38b680
 
 
c95c225
6947b76
6679480
51fd03b
cdddabb
6679480
cdddabb
58c0d2a
d38b680
c646bbc
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
#!/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")