training.mdx 15.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--Copyright 2022 The HuggingFace Team. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
-->

# Fine-tuning a un modelo pre-entrenado

[[open-in-colab]]

Omar U. Espejel's avatar
Omar U. Espejel committed
17
El uso de un modelo pre-entrenado tiene importantes ventajas. Reduce los costos de computaci贸n, la huella de carbono y te permite utilizar modelos de 煤ltima generaci贸n sin tener que entrenar uno desde cero.
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

* Fine-tuning a un modelo pre-entrenado con 馃 Transformers [`Trainer`].
* Fine-tuning a un modelo pre-entrenado en TensorFlow con Keras.
* Fine-tuning a un modelo pre-entrenado en PyTorch nativo.

<a id='data-processing'></a>

## Prepara un dataset

<Youtube id="_BZearw7f0w"/>

Antes de aplicar fine-tuning a un modelo pre-entrenado, descarga un dataset y prep谩ralo para el entrenamiento. El tutorial anterior nos ense帽贸 c贸mo procesar los datos para el entrenamiento, y ahora es la oportunidad de poner a prueba estas habilidades.

Comienza cargando el dataset de [Yelp Reviews](https://huggingface.co/datasets/yelp_review_full):

```py
>>> from datasets import load_dataset

>>> dataset = load_dataset("yelp_review_full")
>>> dataset[100]
{'label': 0,
 'text': 'My expectations for McDonalds are t rarely high. But for one to still fail so spectacularly...that takes something special!\\nThe cashier took my friends\'s order, then promptly ignored me. I had to force myself in front of a cashier who opened his register to wait on the person BEHIND me. I waited over five minutes for a gigantic order that included precisely one kid\'s meal. After watching two people who ordered after me be handed their food, I asked where mine was. The manager started yelling at the cashiers for \\"serving off their orders\\" when they didn\'t have their food. But neither cashier was anywhere near those controls, and the manager was the one serving food to customers and clearing the boards.\\nThe manager was rude when giving me my order. She didn\'t make sure that I had everything ON MY RECEIPT, and never even had the decency to apologize that I felt I was getting poor service.\\nI\'ve eaten at various McDonalds restaurants for over 30 years. I\'ve worked at more than one location. I expect bad days, bad moods, and the occasional mistake. But I have yet to have a decent experience at this store. It will remain a place I avoid unless someone in my party needs to avoid illness from low blood sugar. Perhaps I should go back to the racially biased service of Steak n Shake instead!'}
```

42
Como ya sabes, necesitas un tokenizador para procesar el texto e incluir una estrategia para el padding y el truncamiento para manejar cualquier longitud de secuencia variable. Para procesar tu dataset en un solo paso, utiliza el m茅todo de 馃 Datasets聽map para aplicar una funci贸n de preprocesamiento sobre todo el dataset:
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

```py
>>> from transformers import AutoTokenizer

>>> tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")


>>> def tokenize_function(examples):
...     return tokenizer(examples["text"], padding="max_length", truncation=True)


>>> tokenized_datasets = dataset.map(tokenize_function, batched=True)
```

Si lo deseas, puedes crear un subconjunto m谩s peque帽o del dataset completo para aplicarle fine-tuning y as铆 reducir el tiempo.

```py
>>> small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
>>> small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))
```

<a id='trainer'></a>

## Fine-tuning con `Trainer`

<Youtube id="nvBXf7s7vTI"/>

馃 Transformers proporciona una clase [`Trainer`] optimizada para el entrenamiento de modelos de 馃 Transformers, haciendo m谩s f谩cil el inicio del entrenamiento sin necesidad de escribir manualmente tu propio ciclo. La API del [`Trainer`] soporta una amplia gama de opciones de entrenamiento y caracter铆sticas como el logging, el gradient accumulation y el mixed precision.

Comienza cargando tu modelo y especifica el n煤mero de labels previstas. A partir del [Card Dataset](https://huggingface.co/datasets/yelp_review_full#data-fields) de Yelp Review, que como ya sabemos tiene 5 labels:

```py
>>> from transformers import AutoModelForSequenceClassification

>>> model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)
```

<Tip>

Omar U. Espejel's avatar
Omar U. Espejel committed
82
Ver谩s una advertencia acerca de que algunos de los pesos pre-entrenados no est谩n siendo utilizados y que algunos pesos est谩n siendo inicializados al azar. No te preocupes, esto es completamente normal.
83
El head/cabezal pre-entrenado del modelo BERT se descarta y se sustituye por un head de clasificaci贸n inicializado aleatoriamente. Puedes aplicar fine-tuning a este nuevo head del modelo en tu tarea de clasificaci贸n de secuencias haciendo transfer learning del modelo pre-entrenado.
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

</Tip>

### Hiperpar谩metros de entrenamiento

A continuaci贸n, crea una clase [`TrainingArguments`] que contenga todos los hiperpar谩metros que puedes ajustar as铆 como los indicadores para activar las diferentes opciones de entrenamiento. Para este tutorial puedes empezar con los [hiperpar谩metros](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments) de entrenamiento por defecto, pero si茅ntete libre de experimentar con ellos para encontrar tu configuraci贸n 贸ptima.

Especifica d贸nde vas a guardar los checkpoints de tu entrenamiento:

```py
>>> from transformers import TrainingArguments

>>> training_args = TrainingArguments(output_dir="test_trainer")
```

### M茅tricas

Omar U. Espejel's avatar
Omar U. Espejel committed
101
El [`Trainer`] no eval煤a autom谩ticamente el rendimiento del modelo durante el entrenamiento. Tendr谩s que pasarle a [`Trainer`] una funci贸n para calcular y hacer un reporte de las m茅tricas. La biblioteca de 馃 Datasets proporciona una funci贸n de [`accuracy`](https://huggingface.co/metrics/accuracy) simple que puedes cargar con la funci贸n `load_metric` (ver este [tutorial](https://huggingface.co/docs/datasets/metrics.html) para m谩s informaci贸n):
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

```py
>>> import numpy as np
>>> from datasets import load_metric

>>> metric = load_metric("accuracy")
```

Define la funci贸n `compute` en `metric` para calcular el accuracy de tus predicciones. Antes de pasar tus predicciones a `compute`, necesitas convertir las predicciones a logits (recuerda que todos los modelos de 馃 Transformers devuelven logits).

```py
>>> def compute_metrics(eval_pred):
...     logits, labels = eval_pred
...     predictions = np.argmax(logits, axis=-1)
...     return metric.compute(predictions=predictions, references=labels)
```

Si quieres controlar tus m茅tricas de evaluaci贸n durante el fine-tuning, especifica el par谩metro `evaluation_strategy` en tus argumentos de entrenamiento para que el modelo tenga en cuenta la m茅trica de evaluaci贸n al final de cada 茅poca:

```py
>>> from transformers import TrainingArguments

>>> training_args = TrainingArguments(output_dir="test_trainer", evaluation_strategy="epoch")
```

### Trainer

Omar U. Espejel's avatar
Omar U. Espejel committed
129
Crea un objeto [`Trainer`] con tu modelo, argumentos de entrenamiento, datasets de entrenamiento y de prueba, y tu funci贸n de evaluaci贸n:
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

```py
>>> trainer = Trainer(
...     model=model,
...     args=training_args,
...     train_dataset=small_train_dataset,
...     eval_dataset=small_eval_dataset,
...     compute_metrics=compute_metrics,
... )
```

A continuaci贸n, aplica fine-tuning a tu modelo llamando [`~transformers.Trainer.train`]:

```py
>>> trainer.train()
```

<a id='keras'></a>

## Fine-tuning con Keras

<Youtube id="rnTGBy2ax1c"/>

Omar U. Espejel's avatar
Omar U. Espejel committed
153
Los modelos de 馃 Transformers tambi茅n permiten realizar el entrenamiento en TensorFlow con la API de Keras. Solo es necesario hacer algunos cambios antes de hacer fine-tuning.
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

### Convierte el dataset al formato de TensorFlow

El [`DefaultDataCollator`] junta los tensores en un batch para que el modelo se entrene en 茅l. Aseg煤rate de especificar `return_tensors` para devolver los tensores de TensorFlow:

```py
>>> from transformers import DefaultDataCollator

>>> data_collator = DefaultDataCollator(return_tensors="tf")
```

<Tip>

[`Trainer`] utiliza [`DataCollatorWithPadding`] por defecto por lo que no es necesario especificar expl铆citamente un intercalador de datos (data collator, en ingl茅s).

</Tip>

A continuaci贸n, convierte los datasets tokenizados en datasets de TensorFlow con el m茅todo [`to_tf_dataset`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.to_tf_dataset). Especifica tus entradas en `columns` y tu etiqueta en `label_cols`:

```py
>>> tf_train_dataset = small_train_dataset.to_tf_dataset(
...     columns=["attention_mask", "input_ids", "token_type_ids"],
...     label_cols=["labels"],
...     shuffle=True,
...     collate_fn=data_collator,
...     batch_size=8,
... )

>>> tf_validation_dataset = small_eval_dataset.to_tf_dataset(
...     columns=["attention_mask", "input_ids", "token_type_ids"],
...     label_cols=["labels"],
...     shuffle=False,
...     collate_fn=data_collator,
...     batch_size=8,
... )
```

### Compila y ajusta

Carguemos un modelo TensorFlow con el n煤mero esperado de labels:

```py
>>> import tensorflow as tf
>>> from transformers import TFAutoModelForSequenceClassification

>>> model = TFAutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)
```

A continuaci贸n, compila y aplica fine-tuning a tu modelo con [`fit`](https://keras.io/api/models/model_training_apis/) como lo har铆as con cualquier otro modelo de Keras:

```py
>>> model.compile(
...     optimizer=tf.keras.optimizers.Adam(learning_rate=5e-5),
...     loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
...     metrics=tf.metrics.SparseCategoricalAccuracy(),
... )

>>> model.fit(tf_train_dataset, validation_data=tf_validation_dataset, epochs=3)
```

<a id='pytorch_native'></a>

## Fine-tune en PyTorch nativo

<Youtube id="Dh9CL8fyG80"/>

Omar U. Espejel's avatar
Omar U. Espejel committed
220
El [`Trainer`] se encarga del ciclo de entrenamiento y permite aplicar fine-tuning a un modelo en una sola l铆nea de c贸digo. Para los que prefieran escribir su propio ciclo de entrenamiento, tambi茅n pueden aplicar fine-tuning a un modelo de 馃 Transformers en PyTorch nativo.
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

En este punto, es posible que necesites reiniciar tu notebook o ejecutar el siguiente c贸digo para liberar algo de memoria:

```py
del model
del pytorch_model
del trainer
torch.cuda.empty_cache()
```

A continuaci贸n, haremos un post-procesamiento manual al `tokenized_dataset` y as铆 prepararlo para el entrenamiento.

1. Elimina la columna de `text` porque el modelo no acepta texto en crudo como entrada:

    ```py
    >>> tokenized_datasets = tokenized_datasets.remove_columns(["text"])
    ```

2. Cambia el nombre de la columna de `label` a `labels` porque el modelo espera que el argumento se llame `labels`:

    ```py
    >>> tokenized_datasets = tokenized_datasets.rename_column("label", "labels")
    ```

3. Establece el formato del dataset para devolver tensores PyTorch en lugar de listas:

    ```py
    >>> tokenized_datasets.set_format("torch")
    ```

Omar U. Espejel's avatar
Omar U. Espejel committed
251
A continuaci贸n, crea un subconjunto m谩s peque帽o del dataset como se ha mostrado anteriormente para acelerar el fine-tuning:
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

```py
>>> small_train_dataset = tokenized_datasets["train"].shuffle(seed=42).select(range(1000))
>>> small_eval_dataset = tokenized_datasets["test"].shuffle(seed=42).select(range(1000))
```

### DataLoader

Crea un `DataLoader` para tus datasets de entrenamiento y de prueba para poder iterar sobre batches de datos:

```py
>>> from torch.utils.data import DataLoader

>>> train_dataloader = DataLoader(small_train_dataset, shuffle=True, batch_size=8)
>>> eval_dataloader = DataLoader(small_eval_dataset, batch_size=8)
```

Carga tu modelo con el n煤mero de labels previstas:

```py
>>> from transformers import AutoModelForSequenceClassification

>>> model = AutoModelForSequenceClassification.from_pretrained("bert-base-cased", num_labels=5)
```

Omar U. Espejel's avatar
Omar U. Espejel committed
277
### Optimiza y programa el learning rate
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

Crea un optimizador y el learning rate para aplicar fine-tuning al modelo. Vamos a utilizar el optimizador [`AdamW`](https://pytorch.org/docs/stable/generated/torch.optim.AdamW.html) de PyTorch:

```py
>>> from torch.optim import AdamW

>>> optimizer = AdamW(model.parameters(), lr=5e-5)
```

Crea el learning rate desde el [`Trainer`]:

```py
>>> from transformers import get_scheduler

>>> num_epochs = 3
>>> num_training_steps = num_epochs * len(train_dataloader)
>>> lr_scheduler = get_scheduler(
...     name="linear", optimizer=optimizer, num_warmup_steps=0, num_training_steps=num_training_steps
... )
```

Por 煤ltimo, especifica el `device` o entorno de ejecuci贸n para utilizar una GPU si tienes acceso a una. De lo contrario, el entrenamiento en una CPU puede llevarte varias horas en lugar de un par de minutos.

```py
>>> import torch

>>> device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
>>> model.to(device)
```

<Tip>

Consigue acceso gratuito a una GPU en la nube si es que no tienes este recurso de forma local con un notebook alojado en [Colaboratory](https://colab.research.google.com/) o [SageMaker StudioLab](https://studiolab.sagemaker.aws/).

</Tip>

Omar U. Espejel's avatar
Omar U. Espejel committed
314
Genial, 隆ahora podemos entrenar! 馃コ
315
316
317

### Ciclo de entrenamiento

Omar U. Espejel's avatar
Omar U. Espejel committed
318
Para hacer un seguimiento al progreso del entrenamiento, utiliza la biblioteca [tqdm](https://tqdm.github.io/) para a帽adir una barra de progreso sobre el n煤mero de pasos de entrenamiento:
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

```py
>>> from tqdm.auto import tqdm

>>> progress_bar = tqdm(range(num_training_steps))

>>> model.train()
>>> for epoch in range(num_epochs):
...     for batch in train_dataloader:
...         batch = {k: v.to(device) for k, v in batch.items()}
...         outputs = model(**batch)
...         loss = outputs.loss
...         loss.backward()

...         optimizer.step()
...         lr_scheduler.step()
...         optimizer.zero_grad()
...         progress_bar.update(1)
```

### M茅tricas

De la misma manera que necesitas a帽adir una funci贸n de evaluaci贸n al [`Trainer`], necesitas hacer lo mismo cuando escribas tu propio ciclo de entrenamiento. Pero en lugar de calcular y reportar la m茅trica al final de cada 茅poca, esta vez acumular谩s todos los batches con [`add_batch`](https://huggingface.co/docs/datasets/package_reference/main_classes.html?highlight=add_batch#datasets.Metric.add_batch) y calcular谩s la m茅trica al final.

```py
>>> metric = load_metric("accuracy")
>>> model.eval()
>>> for batch in eval_dataloader:
...     batch = {k: v.to(device) for k, v in batch.items()}
...     with torch.no_grad():
...         outputs = model(**batch)

...     logits = outputs.logits
...     predictions = torch.argmax(logits, dim=-1)
...     metric.add_batch(predictions=predictions, references=batch["labels"])

>>> metric.compute()
```

<a id='additional-resources'></a>

## Recursos adicionales

Para m谩s ejemplos de fine-tuning consulta:

364
- [馃 Transformers Examples](https://github.com/huggingface/transformers/tree/main/examples) incluye scripts
365
366
367
  para entrenar tareas comunes de NLP en PyTorch y TensorFlow.

- [馃 Transformers Notebooks](notebooks) contiene varios notebooks sobre c贸mo aplicar fine-tuning a un modelo para tareas espec铆ficas en PyTorch y TensorFlow.