File size: 9,168 Bytes
5e845b4 |
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 |
# -*- coding: utf-8 -*-
"""Training Llama 3.1.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/19LthnXISqvXgzE-1S2crf-PtTv3OaRmo
# **TRAINING DEL MODELO**
**Instalación de dependencias**
"""
# Commented out IPython magic to ensure Python compatibility.
# %%capture
# !pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
# !pip install --no-deps "xformers<0.0.27" "trl<0.9.0" peft accelerate bitsandbytes
# !pip install datasets # Se instalan
from unsloth import FastLanguageModel # Normalmente se utiliza transformers, pero esta es una librería que permite finetunear rápidamente modelos de lenguaje
import torch
max_seq_length = 2048 # Se puede elegir cualquier largo. Esta librería permite autoscaling (escala automáticamente si el dataset cuenta con un máximo mayor)
dtype = None
load_in_4bit = True # Cuantificación 4bit para reducir el uso de memoria
model, tokenizer = FastLanguageModel.from_pretrained(
model_name = "unsloth/Meta-Llama-3.1-8B-Instruct", # Modelo Llama 3.1 pre-entrenado para la respuesta a instrucciones
max_seq_length = max_seq_length,
dtype = dtype,
load_in_4bit = load_in_4bit,
)
"""**Definición de los Lora Adapters**"""
model = FastLanguageModel.get_peft_model(
model,
r = 16, # Configura el número de parámetros de rango para LoRA. Se recomienda usar valores como 8, 16, 32, 64, 128.
target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",],
lora_alpha = 16, # Establece el valor de alpha para LoRA. Es un hiperparámetro que controla la intensidad de la adaptación de LoRA.
lora_dropout = 0, # Configura la tasa de abandono para LoRA. Se puede usar cualquier valor, pero 0 es la configuración más optimizada.
bias = "none", # Determina el tipo de sesgo para LoRA. La opción "none" es la más optimizada y elimina el sesgo en el modelo.
# [NUEVO] La opción "unsloth" reduce el uso de VRAM en un 30% y permite tamaños de lote hasta 2 veces mayores.
use_gradient_checkpointing = "unsloth", # Usa True o "unsloth" para habilitar el registro de puntos de control de gradientes, lo que es útil para contextos muy largos.
random_state = 3407, # Establece la semilla para la generación de números aleatorios, asegurando reproducibilidad en el entrenamiento.
use_rslora = False, # Indica si se utiliza LoRA con rango estabilizado, que puede mejorar la estabilidad del entrenamiento.
loftq_config = None, # Configura LoftQ si se requiere. LoftQ es una técnica adicional que puede ser utilizada en el modelo.
)
"""**Preparación del dataset**"""
alpaca_prompt = """Below is an instruction that describes a task, with an input that gives more context. Write a response that appropriately completes the request.
### Instruction:
Below you have a sentence in quotation marks. Provide the syntactic category of each word in the context of the sentence.
### Sentence:
"{}"
### Response:
{}"""
EOS_TOKEN = tokenizer.eos_token # Must add EOS_TOKEN
def formatting_prompts_func(examples):
length= len(examples["sentence"])
sentences = examples["sentence"]
tags = examples["sentence_tagged"]
texts = []
for sentence,tag in zip(sentences,tags):
# Must add EOS_TOKEN, otherwise your generation will go on forever!
text = alpaca_prompt.format(sentence,tag) + EOS_TOKEN
texts.append(text)
return { "text" : texts, }
pass
from datasets import load_dataset
dataset = load_dataset("manupinasco/syntax_analysis")
dataset_train = dataset["train"].map(formatting_prompts_func, batched = True,)
dataset_test = dataset["test"]
"""**Prueba pre-entrenamiento**"""
FastLanguageModel.for_inference(model) # Enable native 2x faster inference
for sentence in dataset_test["sentence"][:5]:
inputs = tokenizer(
[
alpaca_prompt.format(
"Below you have a sentence in quotation marks. Provide the syntactic category of each word in the context of the sentence.", # instruction
f' "{sentence}" ', # input
"", # output - leave this blank for generation!
)
], return_tensors = "pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True)
response = str(tokenizer.batch_decode(outputs))
response=response.split("Response:")[1].replace("']", "").replace("\\n", "").replace("<|eot_id|>", "").lstrip()
print("INPUT: "+sentence+"/// RESPONSE: "+response)
"""**Testeo pre-entrenamiento**"""
total = len(dataset_train["sentence"])
correct = 0
i=0
for sentence in dataset_test["sentence"]:
inputs = tokenizer(
[
alpaca_prompt.format(
"Below you have a sentence in quotation marks. Provide the syntactic category of each word in the context of the sentence.", # instruction
f' "{sentence}" ', # input
"", # output - leave this blank for generation!
)
], return_tensors = "pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True)
response = str(tokenizer.batch_decode(outputs))
response=response.split("Response:")[1].replace("']", "").replace("\\n", "").replace("<|eot_id|>", "").lstrip()
if response.lower()==dataset_test["sentence_tagged"][i].lower():
correct+=1
print("RESPONSE: "+response)
print("CORRECT_RESPONSE: "+dataset_test["sentence_tagged"][i])
print("CORRECT RESPONSES SO FAR: "+correct)
print("NUMBER OF SENTENCE: "+i)
i+=1
print("CORRECT "+correct+" OUT OF "+total+". PERCENTAGE "+(correct/total)*100)
"""**Entrenamiento del modelo**
* *Epoch*: cantidad de veces que recorre el dataset completo
* *Batch*: cantidad de subgrupos en los que divide al dataset.
* Entrenamiento común: cada vez que se recorre un batch, se updatean los weights.
* Entrenamiento por **gradient accumulation**: para casos donde se cuente con poca memoria. Sirve para ir acumulando el gradiente de las distintas partes del batch de forma tal de no computar el gradiente recién al finalizarlo.
* En el caso de gradient accumulation, el batch size es = batch size per device x gradient accumulation steps.
* *Batch size*: partes en las que realmente dividí al conjunto de datos.
* *Batch size per device*: partes en las que dividí al conjunto de datos para, al terminar de recorrer cada una de estas partes, hacer un update de los weights.
* *Gradient accumulation steps*: veces que, por cada batch size per device, acumulé las gradientes previo al update de los weights.
"""
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported
trainer = SFTTrainer(
model = model,
tokenizer = tokenizer,
train_dataset = dataset_train,
dataset_text_field = "text",
max_seq_length = max_seq_length,
dataset_num_proc = 2,
packing = False, # Puede hacer el entrenamiento 5x más rápido para oraciones breves.
args = TrainingArguments(
per_device_train_batch_size = 2,
gradient_accumulation_steps = 4,
warmup_steps = 5,
# num_train_epochs = 1, # Si se setea a 1 hace una corrida completa por todo el dataset.
max_steps = 60,
learning_rate = 2e-4,
fp16 = not is_bfloat16_supported(),
bf16 = is_bfloat16_supported(),
logging_steps = 1,
optim = "adamw_8bit",
weight_decay = 0.01,
lr_scheduler_type = "linear",
seed = 3407,
output_dir = "outputs",
),
)
trainer_stats = trainer.train()
"""# **TESTEO DEL MODELO**
**Prueba post-entrenamiento**
"""
FastLanguageModel.for_inference(model) # Enable native 2x faster inference
for sentence in dataset_test["sentence"][:5]:
inputs = tokenizer(
[
alpaca_prompt.format(
f' "{sentence}" ', # input
"", # output - leave this blank for generation!
)
], return_tensors = "pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True)
response = str(tokenizer.batch_decode(outputs))
response=response.split("Response:")[1].replace("']", "").replace("\\n", "").replace("<|eot_id|>", "").lstrip()
print("INPUT: "+sentence+"/// RESPONSE: "+response)
"""**Testeo post-entrenamiento**"""
total = len(dataset_train["sentence"])
correct = 0
i=0
for sentence in dataset_test["sentence"]:
inputs = tokenizer(
[
alpaca_prompt.format(
f' "{sentence}" ', # input
"", # output - leave this blank for generation!
)
], return_tensors = "pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens = 64, use_cache = True)
response = str(tokenizer.batch_decode(outputs))
response=response.split("Response:")[1].replace("']", "").replace("\\n", "").replace("<|eot_id|>", "").lstrip()
if response.lower()==dataset_test["sentence_tagged"][i].lower():
correct+=1
print("RESPONSE: "+response)
print("CORRECT_RESPONSE: "+dataset_test["sentence_tagged"][i])
print("CORRECT RESPONSES SO FAR: "+correct)
print("NUMBER OF SENTENCE: "+i)
i+=1
print("CORRECT "+correct+" OUT OF "+total+". PERCENTAGE "+(correct/total)*100) |