From dde99d85dfb7a9448df7b0298a4c4bc8a7ee99ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Grandury?= Date: Tue, 17 Oct 2023 13:29:22 +0200 Subject: [PATCH] translate code comments to Spanish and fix typos --- chapters/es/chapter0/1.mdx | 10 +- chapters/es/chapter1/10.mdx | 318 ++++++++++++++++++------------------ chapters/es/chapter2/4.mdx | 25 +-- chapters/es/chapter2/6.mdx | 32 ++-- chapters/es/chapter3/1.mdx | 6 +- chapters/es/chapter3/2.mdx | 48 +++--- chapters/es/chapter3/4.mdx | 29 ++-- chapters/es/chapter5/4.mdx | 9 +- 8 files changed, 245 insertions(+), 232 deletions(-) diff --git a/chapters/es/chapter0/1.mdx b/chapters/es/chapter0/1.mdx index 41a65887b..e2d6f55f9 100644 --- a/chapters/es/chapter0/1.mdx +++ b/chapters/es/chapter0/1.mdx @@ -12,14 +12,14 @@ La mayor parte del curso depende de que tengas una cuenta de Hugging Face. Te re ## Uso de un cuaderno Google Colab -Utilizar un cuaderno Colab es la configuración más sencilla posible; ¡arranca un cuaderno en tu navegador y ponte a codificar directamente! +Utilizar un cuaderno Colab es la configuración más sencilla posible; ¡arranca un cuaderno en tu navegador y ponte a codificar directamente! Si no estás familiarizado con Colab, te recomendamos que empieces siguiendo la [introducción](https://colab.research.google.com/notebooks/intro.ipynb). Colab te permite utilizar algún hardware de aceleración, como GPUs o TPUs, y es gratuito para cargas de trabajo pequeñas. Una vez que te sientas cómodo moviéndote en Colab, crea un nuevo notebook y comienza con la configuración:
-An empty colab notebook + An empty colab notebook
El siguiente paso es instalar las librerías que usaremos en este curso. Usaremos `pip` para la instalación, que es el gestor de paquetes para Python. En los cuadernos, puedes ejecutar comandos del sistema precediéndolos con el carácter `!`, así que puedes instalar la librería 🤗 Transformers de la siguiente manera: @@ -35,7 +35,7 @@ import transformers ```
-A gif showing the result of the two commands above: installation and import + A gif showing the result of the two commands above: installation and import
Esto instala una versión muy ligera de 🤗 Transformers. En particular, no se instalan frameworks específicos de deep learning (como PyTorch o TensorFlow). Dado que vamos a utilizar un montón de características diferentes de la biblioteca, se recomienda instalar la versión de desarrollo, que viene con todas las dependencias necesarias para casi cualquier caso de uso imaginable: @@ -82,10 +82,10 @@ ls -a Puedes entrar y salir de tu entorno virtual con los scripts `activate` y `deactivate`: ``` -# Activate the virtual environment +# Activa el entorno virtual source .env/bin/activate -# Deactivate the virtual environment +# Desactiva el entorno virtual source .env/bin/deactivate ``` diff --git a/chapters/es/chapter1/10.mdx b/chapters/es/chapter1/10.mdx index 6749eeee5..5cda0cf1b 100644 --- a/chapters/es/chapter1/10.mdx +++ b/chapters/es/chapter1/10.mdx @@ -14,21 +14,21 @@ Por ahora, ¡revisemos lo que aprendiste en este capítulo! ### 1. Explora el Hub y busca el punto de control `roberta-large-mnli`. ¿Qué tarea desarrolla? página de roberta-large-mnli." - }, - { - text: "Clasificación de texto", - explain: " Más precisamente, clasifica si dos oraciones están relacionadas lógicamente a través de tres etiquetas (contradiction, neutral, entailment) - una tarea que también se conoce como inferencia de lenguaje natural.", - correct: true - }, - { - text: "Generación de texto", - explain: "Vuelve a mirar en la página de roberta-large-mnli." + choices={[ + { + text: "Resumen", + explain: "Vuelve a mirar en la página de roberta-large-mnli." + }, + { + text: "Clasificación de texto", + explain: " Más precisamente, clasifica si dos oraciones están relacionadas lógicamente a través de tres etiquetas (contradiction, neutral, entailment) - una tarea que también se conoce como inferencia de lenguaje natural.", + correct: true + }, + { + text: "Generación de texto", + explain: "Vuelve a mirar en la página de roberta-large-mnli." } - ]} + ]} /> ### 2. ¿Qué devuelve el siguiente código? @@ -41,21 +41,21 @@ ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") ``` sentiment-analysis." - }, - { - text: "Devuelve un texto generado que completa esta oración.", - explain: "Incorrecto - esto sería un pipeline de text-generation." - }, - { - text: "Devuelve las palabras que representan personas, organizaciones o ubicaciones.", - explain: "Adicionalmente, con grouped_entities=True, agrupará las palabras que pertenecen a la misma entidad, como \"Hugging Face\".", - correct: true + choices={[ + { + text: "Devuelve los puntajes de clasificación de esta oración, con las etiquetas \"positive\" o \"negative\".", + explain: "Incorrecto - esto sería un pipeline de sentiment-analysis." + }, + { + text: "Devuelve un texto generado que completa esta oración.", + explain: "Incorrecto - esto sería un pipeline de text-generation." + }, + { + text: "Devuelve las palabras que representan personas, organizaciones o ubicaciones.", + explain: "Adicionalmente, con grouped_entities=True, agrupará las palabras que pertenecen a la misma entidad, como \"Hugging Face\".", + correct: true } - ]} + ]} /> ### 3. ¿Qué debería reemplazar ... en este ejemplo de código? @@ -68,21 +68,21 @@ result = filler("...") ``` has been waiting for you.", - explain: "Incorrecto. Revisa la ficha del modelo bert-base-cased e intenta identificar tu error." - }, - { - text: "This [MASK] has been waiting for you.", - explain: "¡Correcto! El mask token de este modelo es [MASK].", - correct: true - }, - { - text: "This man has been waiting for you.", - explain: "Incorrecto. Esrte pipeline llena palabras ocultas, por lo que necesita un mask token en algún lugar." + choices={[ + { + text: "This <mask> has been waiting for you.", + explain: "Incorrecto. Revisa la ficha del modelo bert-base-cased e intenta identificar tu error." + }, + { + text: "This [MASK] has been waiting for you.", + explain: "¡Correcto! El mask token de este modelo es [MASK].", + correct: true + }, + { + text: "This man has been waiting for you.", + explain: "Incorrecto. Este pipeline llena palabras ocultas, por lo que necesita un mask token en algún lugar." } - ]} + ]} /> ### 4. ¿Por qué fallará este código? @@ -95,167 +95,161 @@ result = classifier("This is a course about the Transformers library") ``` candidate_labels=[...].", - correct: true - }, - { - text: "Este pipeline requiere varias oraciones, no sólo una.", - explain: "Incorrecto, aunque cuando se usa adecuadamente, este pipeline puede tomar una lista de oraciones para procesar (como todos los otros pipelines)." - }, - { - text: "La librería 🤗 Transformers está dañada, como siempre.", - explain: "¡No vamos a dignificar esta respuesta con un comentario!" - }, - { - text: "Este pipeline necesita entradas más largas; esta oración es muy corta.", - explain: "Incorrecto. Un texto muy largo se va a truncar cuando se procesa por este pipeline." + choices={[ + { + text: "Este pipeline necesita que se le indiquen etiquetas para clasificar el texto.", + explain: "Correcto — el código necesita incluir candidate_labels=[...].", + correct: true + }, + { + text: "Este pipeline requiere varias oraciones, no sólo una.", + explain: "Incorrecto, aunque cuando se usa adecuadamente, este pipeline puede tomar una lista de oraciones para procesar (como todos los otros pipelines)." + }, + { + text: "La librería 🤗 Transformers está dañada, como siempre.", + explain: "¡No vamos a dignificar esta respuesta con un comentario!" + }, + { + text: "Este pipeline necesita entradas más largas; esta oración es muy corta.", + explain: "Incorrecto. Un texto muy largo se va a truncar cuando se procesa por este pipeline." } - ]} + ]} /> ### 5. ¿Qué significa "transferencia de aprendizaje"? ### 6. ¿Verdadero o falso? Un modelo de lenguaje usualmente no necesita etiquetas para su preentrenamiento. auto-supervisado, lo que significa que las etiquetas se crean automáticamente a partir de la entrada (como predecir la siguiente palabra o llenar palabras ocultas).", - correct: true - }, - { - text: "Falso", - explain: "Esta no es la respuesta correcta." + choices={[ + { + text: "Verdadero", + explain: "El preentrenamiento suele ser auto-supervisado, lo que significa que las etiquetas se crean automáticamente a partir de la entrada (como predecir la siguiente palabra o llenar palabras ocultas).", + correct: true + }, + { + text: "Falso", + explain: "Esta no es la respuesta correcta." } - ]} + ]} /> ### 7. Selecciona la oración que describe mejor los términos "modelo", "arquitectura" y "pesos". -Select the sentence that best describes the terms "model," "architecture," and "weights." - - ### 8. ¿Cuál de los siguientes tipos de modelos usarías para completar una indicación con texto generado? - ### 9. ¿Cuál de los siguientes tipos de modelos usarías para resumir textos? ### 10. ¿Cuál de los siguientes tipos de modelos usarías para clasificar texto de acuerdo con ciertas etiquetas? ### 11. ¿Cuál puede ser una posible fuente del sesgo observado en un modelo? -What possible source can the bias observed in a model have? - diff --git a/chapters/es/chapter2/4.mdx b/chapters/es/chapter2/4.mdx index b20685498..2b3dc986a 100644 --- a/chapters/es/chapter2/4.mdx +++ b/chapters/es/chapter2/4.mdx @@ -9,7 +9,7 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/es/chapter2/section4_pt.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/es/chapter2/section4_pt.ipynb"}, -]} /> + ]} /> {:else} @@ -18,7 +18,7 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/es/chapter2/section4_tf.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/es/chapter2/section4_tf.ipynb"}, -]} /> + ]} /> {/if} @@ -27,11 +27,12 @@ Los tokenizadores son uno de los componentes fundamentales del pipeline en NLP. Sirven para traducir texto en datos que los modelos puedan procesar; es decir, de texto a valores numéricos. En esta sección veremos en qué se fundamenta todo el proceso de tokenizado. En las tareas de NLP, los datos generalmente ingresan como texto crudo. Por ejemplo: + ``` Jim Henson era un titiritero ``` -Sin embargo, necesitamos una forma de convertir el texto crudo a valores numéricos para los modelos. Eso es precisamente lo que hacen los tokenizadores, y existe una variedad de formas en que puede hacerse. El objetivo final es obetener valores que sean cortos pero muy significativos para el modelo. +Sin embargo, necesitamos una forma de convertir el texto crudo a valores numéricos para los modelos. Eso es precisamente lo que hacen los tokenizadores, y existe una variedad de formas en que puede hacerse. El objetivo final es obetener valores que sean cortos pero muy significativos para el modelo. Veamos algunos algoritmos de tokenización, e intentemos atacar algunas preguntas que puedas tener. @@ -40,12 +41,13 @@ Veamos algunos algoritmos de tokenización, e intentemos atacar algunas pregunta El primer tokenizador que nos ocurre es el _word-based_ (_basado-en-palabras_). Es generalmente sencillo, con pocas normas, y generalmente da buenos resultados. Por ejemplo, en la imagen a continuación separamos el texto en palabras y buscamos una representación numérica. +
Un ejemplo de tokenizador _word-based_.
-Existen varias formas de separar el texto. Por ejempĺo, podríamos usar los espacios para tokenizar usando Python y la función `split()`. +Existen varias formas de separar el texto. Por ejempĺo, podríamos usar los espacios para tokenizar usando Python y la función `split()`. ```py tokenized_text = "Jim Henson era un titiritero".split() @@ -55,6 +57,7 @@ print(tokenized_text) ```python out ['Jim', 'Henson', 'era', 'un', 'titiritero'] ``` + También hay variaciones de tokenizadores de palabras que tienen reglas adicionales para la puntuación. Con este tipo de tokenizador, podemos acabar con unos "vocabularios" bastante grandes, donde un vocabulario se define por el número total de tokens independientes que tenemos en nuestro corpus. A cada palabra se le asigna un ID, empezando por 0 y subiendo hasta el tamaño del vocabulario. El modelo utiliza estos ID para identificar cada palabra. @@ -69,13 +72,12 @@ Una forma de reducir la cantidad de tokens desconocidos es ir un poco más allá -Character-based tokenizers split the text into characters, rather than words. This has two primary benefits: -Un tokenizador _character-based_ separa el texto en caracteres, y no en palabras. Conllevando dos beneficios principales: +Un tokenizador _character-based_ separa el texto en caracteres, y no en palabras. Esto conlleva dos beneficios principales: - Obtenemos un vocabulario mucho más corto. -- Habrá muchos menos tokens por fuera del vocabulatio conocido. +- Habrá muchos menos tokens por fuera del vocabulario conocido. -No obstante, pueden surgir incovenientes por los espacios en blanco y signos de puntuación. +No obstante, pueden surgir inconvenientes por los espacios en blanco y signos de puntuación.
Ejemplo de tokenizador basado en palabras. @@ -105,7 +107,7 @@ Este es un ejemplo que muestra cómo un algoritmo de tokenización de subpalabra Estas subpalabras terminan aportando mucho significado semántico: por ejemplo, en el ejemplo anterior, "tokenización" se dividió en "token" y "ización", dos tokens que tienen un significado semántico y a la vez son eficientes en cuanto al espacio (sólo se necesitan dos tokens para representar una palabra larga). Esto nos permite tener una cobertura relativamente buena con vocabularios pequeños y casi sin tokens desconocidos. -Este enfoque es especialmente útil en algunos idimas como el turco, donde se pueden formar palabras complejas (casi) arbitrariamente largas encadenando subpalabras. +Este enfoque es especialmente útil en algunos idiomas como el turco, donde se pueden formar palabras complejas (casi) arbitrariamente largas encadenando subpalabras. ### Y más! @@ -154,6 +156,7 @@ tokenizer("Using a Transformer network is simple") 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} ``` + Guardar un tokenizador es idéntico a guardar un modelo: ```py @@ -200,6 +203,7 @@ Este tokenizador es un tokenizador de subpalabras: divide las palabras hasta obt ### De tokens a IDs de entrada La conversión a IDs de entrada se hace con el método del tokenizador `convert_tokens_to_ids()`: + ```py ids = tokenizer.convert_tokens_to_ids(tokens) @@ -230,6 +234,7 @@ print(decoded_string) ```python out 'Using a Transformer network is simple' ``` + Notemos que el método `decode` no sólo convierte los índices de nuevo en tokens, sino que también agrupa los tokens que formaban parte de las mismas palabras para producir una frase legible. Este comportamiento será extremadamente útil cuando utilicemos modelos que predigan texto nuevo (ya sea texto generado a partir de una indicación, o para problemas de secuencia a secuencia como la traducción o el resumen). -A estas alturas deberías entender las operaciones atómicas que un tokenizador puede manejar: tokenización, conversión a IDs, y conversión de IDs de vuelta a una cadena. Sin embargo, sólo hemos rozado la punta del iceberg. En la siguiente sección, llevaremos nuestro enfoque a sus límites y echaremos un vistazo a cómo superarlos. \ No newline at end of file +A estas alturas deberías entender las operaciones atómicas que un tokenizador puede manejar: tokenización, conversión a IDs, y conversión de IDs de vuelta a una cadena. Sin embargo, sólo hemos rozado la punta del iceberg. En la siguiente sección, llevaremos nuestro enfoque a sus límites y echaremos un vistazo a cómo superarlos. diff --git a/chapters/es/chapter2/6.mdx b/chapters/es/chapter2/6.mdx index 443ee3ee2..155e8754d 100644 --- a/chapters/es/chapter2/6.mdx +++ b/chapters/es/chapter2/6.mdx @@ -9,7 +9,7 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_pt.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_pt.ipynb"}, -]} /> + ]} /> {:else} @@ -18,7 +18,7 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_tf.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter2/section6_tf.ipynb"}, -]} /> + ]} /> {/if} @@ -58,14 +58,14 @@ model_inputs = tokenizer(sequences) Puede rellenar de acuerdo a varios objetivos: ```py -# Will pad the sequences up to the maximum sequence length +# Rellenar las secuencias hasta la mayor longitud de secuencia model_inputs = tokenizer(sequences, padding="longest") -# Will pad the sequences up to the model max length -# (512 for BERT or DistilBERT) +# Rellenar las secuencias hasta la máxima longitud del modelo +# (512 para BERT o DistilBERT) model_inputs = tokenizer(sequences, padding="max_length") -# Will pad the sequences up to the specified max length +# Rellenar las secuencias hasta la máxima longitud especificada model_inputs = tokenizer(sequences, padding="max_length", max_length=8) ``` @@ -74,26 +74,26 @@ También puede truncar secuencias: ```py sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] -# Will truncate the sequences that are longer than the model max length -# (512 for BERT or DistilBERT) +# Truncar las secuencias más largas que la máxima longitud del modelo +# (512 para BERT o DistilBERT) model_inputs = tokenizer(sequences, truncation=True) -# Will truncate the sequences that are longer than the specified max length +# Truncar las secuencias más largas que la longitud especificada model_inputs = tokenizer(sequences, max_length=8, truncation=True) ``` -El objeto `tokenizer` puede manejar la conversión a tensores de frameworks específicos, los cuales pueden ser enviados directametne al modelo. Por ejemplo, en el siguiente código de ejemplo estamos solicitando al tokenizer que regrese los tensores de los distintos frameworks — `"pt"` regresa tensores de PyTorch, `"tf"` regresa tensores de TensorFlow, y `"np"` regresa arreglos de NumPy: +El objeto `tokenizer` puede manejar la conversión a tensores de frameworks específicos, los cuales pueden ser enviados directametne al modelo. Por ejemplo, en el siguiente código de ejemplo estamos solicitando al tokenizer que regrese los tensores de los distintos frameworks — `"pt"` regresa tensores de PyTorch, `"tf"` regresa tensores de TensorFlow, y `"np"` regresa arreglos de NumPy: ```py sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] -# Returns PyTorch tensors +# Devuelve tensores PyTorch model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") -# Returns TensorFlow tensors +# Devuelve tensores TensorFlow model_inputs = tokenizer(sequences, padding=True, return_tensors="tf") -# Returns NumPy arrays +# Devuelve arrays Numpy model_inputs = tokenizer(sequences, padding=True, return_tensors="np") ``` @@ -129,13 +129,14 @@ print(tokenizer.decode(ids)) "i've been waiting for a huggingface course my whole life." ``` -El tokenizador agregó la palabra especial `[CLS]` al principio y la palabra especial `[SEP]` al final. Esto se debe a que el modelo fue preentrenado con esos, así para obtener los mismos resultados por inferencia necesitamos agregarlos también. Nota que algunos modelos no agregan palabras especiales, o agregan unas distintas; los modelos también pueden agregar estas palabras especiales sólo al principio, o sólo al final. En cualquier caso, el tokenizador sabe cuáles son las esperadas y se encargará de ello por tí. +El tokenizador agregó la palabra especial `[CLS]` al principio y la palabra especial `[SEP]` al final. Esto se debe a que el modelo fue preentrenado con esos, así para obtener los mismos resultados por inferencia necesitamos agregarlos también. Nota que algunos modelos no agregan palabras especiales, o agregan unas distintas; los modelos también pueden agregar estas palabras especiales sólo al principio, o sólo al final. En cualquier caso, el tokenizador sabe cuáles son las esperadas y se encargará de ello por tí. ## Conclusión: Del tokenizador al moelo Ahora que hemos visto todos los pasos individuales que el objeto `tokenizer` usa cuando se aplica a textos, veamos una última vez cómo maneja varias secuencias (¡relleno!), secuencias muy largas (¡truncado!), y múltiples tipos de tensores con su API principal: {#if fw === 'pt'} + ```py import torch from transformers import AutoTokenizer, AutoModelForSequenceClassification @@ -148,7 +149,9 @@ sequences = ["I've been waiting for a HuggingFace course my whole life.", "So ha tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") output = model(**tokens) ``` + {:else} + ```py import tensorflow as tf from transformers import AutoTokenizer, TFAutoModelForSequenceClassification @@ -161,4 +164,5 @@ sequences = ["I've been waiting for a HuggingFace course my whole life.", "So ha tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="tf") output = model(**tokens) ``` + {/if} diff --git a/chapters/es/chapter3/1.mdx b/chapters/es/chapter3/1.mdx index 867002e31..f37308113 100644 --- a/chapters/es/chapter3/1.mdx +++ b/chapters/es/chapter3/1.mdx @@ -7,15 +7,17 @@ classNames="absolute z-10 right-0 top-0" /> -En el [Capítulo 2](/course/chapter2) exploramos como usar los tokenizadores y modelos preentrenados para realizar predicciones. Pero qué tal si deseas ajustar un modelo preentrenado con tu propio conjunto de datos ? +En el [Capítulo 2](/course/chapter2) exploramos cómo usar los tokenizadores y modelos preentrenados para realizar predicciones. Pero, ¿qué pasa si deseas ajustar un modelo preentrenado con tu propio conjunto de datos? {#if fw === 'pt'} + * Cómo preparar un conjunto de datos grande desde el Hub. * Cómo usar la API de alto nivel del entrenador para ajustar un modelo. * Cómo usar un bucle personalizado de entrenamiento. -* Cómo aprovechar la Accelerate library 🤗 para fácilmente ejecutar el bucle personalizado de entrenamiento en cualquier configuración distribuida. +* Cómo aprovechar la librería 🤗 Accelerate para fácilmente ejecutar el bucle personalizado de entrenamiento en cualquier configuración distribuida. {:else} + * Cómo preparar un conjunto de datos grande desde el Hub. * Cómo usar Keras para ajustar un modelo. * Cómo usar Keras para obtener predicciones. diff --git a/chapters/es/chapter3/2.mdx b/chapters/es/chapter3/2.mdx index eded26291..dfc0099da 100644 --- a/chapters/es/chapter3/2.mdx +++ b/chapters/es/chapter3/2.mdx @@ -9,7 +9,7 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/es/chapter3/section2_pt.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/es/chapter3/section2_pt.ipynb"}, -]} /> + ]} /> {:else} @@ -18,7 +18,7 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/es/chapter3/section2_tf.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/es/chapter3/section2_tf.ipynb"}, -]} /> + ]} /> {/if} @@ -47,6 +47,7 @@ loss = model(**batch).loss loss.backward() optimizer.step() ``` + {:else} Continuando con el ejemplo del [capítulo anterior](/course/chapter2), aquí mostraremos como podríamos entrenar un clasificador de oraciones/sentencias en TensorFlow: @@ -70,6 +71,7 @@ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy") labels = tf.convert_to_tensor([1, 1]) model.train_on_batch(batch, labels) ``` + {/if} Por supuesto, entrenando el modelo con solo dos oraciones no va a producir muy buenos resultados. Para obtener mejores resultados, debes preparar un conjunto de datos más grande. @@ -79,6 +81,7 @@ En esta sección usaremos como ejemplo el conjunto de datos MRPC (Cuerpo de par ### Cargando un conjunto de datos desde el Hub {#if fw === 'pt'} + {:else} @@ -86,7 +89,7 @@ En esta sección usaremos como ejemplo el conjunto de datos MRPC (Cuerpo de par El Hub no solo contiene modelos; sino que también tiene múltiples conjunto de datos en diferentes idiomas. Puedes explorar los conjuntos de datos [aquí](https://huggingface.co/datasets), y recomendamos que trates de cargar y procesar un nuevo conjunto de datos una vez que hayas revisado esta sección (mira la documentación general [aquí](https://huggingface.co/docs/datasets/loading_datasets.html#from-the-huggingface-hub)). Por ahora, enfoquémonos en el conjunto de datos MRPC! Este es uno de los 10 conjuntos de datos que comprende el [punto de referencia GLUE](https://gluebenchmark.com/), el cual es un punto de referencia académico que se usa para medir el desempeño de modelos ML sobre 10 tareas de clasificación de texto. -La Libreria Datasets 🤗 provee un comando muy simple para descargar y memorizar un conjunto de datos en el Hub. Podemos descargar el conjunto de datos de la siguiente manera: +La librería 🤗 Datasets provee un comando muy simple para descargar y memorizar un conjunto de datos en el Hub. Podemos descargar el conjunto de datos de la siguiente manera: ```py from datasets import load_dataset @@ -154,6 +157,7 @@ Internamente, `label` es del tipo de dato `ClassLabel`, y la asociación de valo ### Preprocesando un conjunto de datos {#if fw === 'pt'} + {:else} @@ -179,7 +183,7 @@ inputs ``` ```python out -{ +{ 'input_ids': [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102], 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] @@ -192,7 +196,6 @@ Nosotros consideramos las llaves `input_ids` y `attention_mask` en el [Capítulo ✏️ **Inténtalo!** Toma el elemento 15 del conjunto de datos de entrenamiento y tokeniza las dos oraciones independientemente y como un par. Cuál es la diferencia entre los dos resultados? - Si convertimos los IDs dentro de `input_ids` en palabras: @@ -216,15 +219,15 @@ De esta manera vemos que el modelo espera las entradas de la siguiente forma `[C Como puedes observar, las partes de la entrada que corresponden a `[CLS] sentence1 [SEP]` todas tienen un tipo de token ID `0`, mientras que las otras partes que corresponden a `sentence2 [SEP]`, todas tienen tipo ID `1`. -Nótese que si seleccionas un punto de control diferente, no necesariamente tendrás el `token_type_ids` en tus entradas tonenizadas (por ejemplo, ellas no aparecen si usas un modelo DistilBERT). Estas aparecen cuando el modelo sabe que hacer con ellas, porque las ha visto durante su etapa de preentrenamiento. +Nótese que si seleccionas un punto de control diferente, no necesariamente tendrás el `token_type_ids` en tus entradas tokenizadas (por ejemplo, ellas no aparecen si usas un modelo DistilBERT). Estas aparecen cuando el modelo sabe que hacer con ellas, porque las ha visto durante su etapa de preentrenamiento. -Aquí, BERT esta preentrenado con tokens de tipo ID, y además del objetivo de modelado de lenguaje oculto que mencionamos en el [Capítulo 1](/course/chapter1), también tiene el objetivo llamado _predicción de la siguiente oración_. El objectivo con esta tarea es modelar la relación entre pares de oraciones. +Aquí, BERT está preentrenado con tokens de tipo ID, y además del objetivo de modelado de lenguaje oculto que mencionamos en el [Capítulo 1](/course/chapter1), también tiene el objetivo llamado _predicción de la siguiente oración_. El objetivo con esta tarea es modelar la relación entre pares de oraciones. -Para predecir la siguiente oración, el modelo recibe pares de oraciones (con tokens ocultados aleatoriamente) y se le pide que prediga si la segunda secuencia sigue a la primera. Para que la tarea no sea tan simple, la mitad de las veces las oraciones estan seguidas en el texto original de donde se obtuvieron, y la otra mitad las oraciones vienen de dos documentos distintos. +Para predecir la siguiente oración, el modelo recibe pares de oraciones (con tokens ocultados aleatoriamente) y se le pide que prediga si la segunda secuencia sigue a la primera. Para que la tarea no sea tan simple, la mitad de las veces las oraciones están seguidas en el texto original de donde se obtuvieron, y la otra mitad las oraciones vienen de dos documentos distintos. -En general, no debes preocuparte si los `token_type_ids` estan o no en las entradas tokenizadas: con tal que uses el mismo punto de control para el tokenizador y el modelo, todo estará bien porque el tokenizador sabe que pasarle a su modelo. +En general, no debes preocuparte si los `token_type_ids` están o no en las entradas tokenizadas: con tal de que uses el mismo punto de control para el tokenizador y el modelo, todo estará bien porque el tokenizador sabe qué pasarle a su modelo. -Ahora que hemos visto como nuestro tokenizador puede trabajar con un par de oraciones, podemos usarlo para tokenizar todo el conjunto de datos: como en el [capítulo anterior](/course/chapter2), podemos darle al tokenizador una lista de pares de oraciones, dándole la lista de las primeras oraciones, y luego la lista de las segundas oraciones. Esto también es compatible con las opciones de relleno y truncamiento que vimos en el [Capítulo 2](/course/chapter2). Por lo tanto, una manera de preprocessar el conjunto de datos de entrenamiento sería: +Ahora que hemos visto como nuestro tokenizador puede trabajar con un par de oraciones, podemos usarlo para tokenizar todo el conjunto de datos: como en el [capítulo anterior](/course/es/chapter2), podemos darle al tokenizador una lista de pares de oraciones, dándole la lista de las primeras oraciones, y luego la lista de las segundas oraciones. Esto también es compatible con las opciones de relleno y truncamiento que vimos en el [Capítulo 2](/course/chapter2). Por lo tanto, una manera de preprocesar el conjunto de datos de entrenamiento sería: ```py tokenized_dataset = tokenizer( @@ -235,7 +238,7 @@ tokenized_dataset = tokenizer( ) ``` -Esto funciona bien, pero tiene la desventaja de que devuelve un diccionario (con nuestras llaves, `input_ids`, `attention_mask`, and `token_type_ids`, y valores que son listas de listas). Además va a trabajar solo si tienes suficiente memoria principal para almacenar todo el conjunto de datos durante la tokenización (mientras que los conjuntos de datos de la librería Datasets 🤗 son archivos [Apache Arrow](https://arrow.apache.org/) almacenados en disco, y así solo mantienes en memoria las muestras que necesitas). +Esto funciona bien, pero tiene la desventaja de que devuelve un diccionario (con nuestras llaves, `input_ids`, `attention_mask`, and `token_type_ids`, y valores que son listas de listas). Además va a trabajar solo si tienes suficiente memoria principal para almacenar todo el conjunto de datos durante la tokenización (mientras que los conjuntos de datos de la librería 🤗 Datasets son archivos [Apache Arrow](https://arrow.apache.org/) almacenados en disco, y así solo mantienes en memoria las muestras que necesitas). Para mantener los datos como un conjunto de datos, usaremos el método [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes.html#datasets.Dataset.map). Este también nos ofrece una flexibilidad adicional en caso de que necesitemos preprocesamiento mas allá de la tokenización. El método `map()` trabaja aplicando una función sobre cada elemento del conjunto de datos, así que definamos una función para tokenizar nuestras entradas: @@ -244,9 +247,9 @@ def tokenize_function(example): return tokenizer(example["sentence1"], example["sentence2"], truncation=True) ``` -Esta función recibe un diccionario (como los elementos de nuestro conjunto de datos) y devuelve un nuevo diccionario con las llaves `input_ids`, `attention_mask`, y `token_type_ids`. Nótese que también funciona si el diccionario `example` contiene múltiples elementos (cada llave con una lista de oraciones) debido a que el `tokenizador` funciona con listas de pares de oraciones, como se vio anteriormente. Esto nos va a permitir usar la opción `batched=True` en nuestra llamada a `map()`, lo que acelera la tokenización significativamente. El `tokenizador` es respaldado por un tokenizador escrito en Rust que viene de la libreria [Tokenizadores 🤗](https://github.com/huggingface/tokenizers). Este tokenizador puede ser muy rápido, pero solo si le da muchas entradas al mismo tiempo. +Esta función recibe un diccionario (como los elementos de nuestro conjunto de datos) y devuelve un nuevo diccionario con las llaves `input_ids`, `attention_mask`, y `token_type_ids`. Nótese que también funciona si el diccionario `example` contiene múltiples elementos (cada llave con una lista de oraciones) debido a que el `tokenizador` funciona con listas de pares de oraciones, como se vio anteriormente. Esto nos va a permitir usar la opción `batched=True` en nuestra llamada a `map()`, lo que acelera la tokenización significativamente. El `tokenizador` es respaldado por un tokenizador escrito en Rust que viene de la librería [🤗 Tokenizers](https://github.com/huggingface/tokenizers). Este tokenizador puede ser muy rápido, pero solo si le da muchas entradas al mismo tiempo. -Nótese que por ahora hemos dejado el argumento `padding` fuera de nuestra función de tokenización. Esto es porque rellenar todos los elementos hasta su máxima longitud no es eficiente: es mejor rellenar los elememtos cuando se esta construyendo el lote, debido a que solo debemos rellenar hasta la máxima longitud en el lote, pero no en todo el conjunto de datos. Esto puede ahorrar mucho tiempo y poder de processamiento cuando las entradas tienen longitudes variables. +Nótese que por ahora hemos dejado el argumento `padding` fuera de nuestra función de tokenización. Esto es porque rellenar todos los elementos hasta su máxima longitud no es eficiente: es mejor rellenar los elementos cuando se esta construyendo el lote, debido a que solo debemos rellenar hasta la máxima longitud en el lote, pero no en todo el conjunto de datos. Esto puede ahorrar mucho tiempo y poder de procesamiento cuando las entradas tienen longitudes variables. Aquí se muestra como se aplica la función de tokenización a todo el conjunto de datos en un solo paso. Estamos usando `batched=True` en nuestra llamada a `map` para que la función sea aplicada a múltiples elementos de nuestro conjunto de datos al mismo tiempo, y no a cada elemento por separado. Esto permite un preprocesamiento más rápido. @@ -255,7 +258,7 @@ tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) tokenized_datasets ``` -La manera en que la libreria 🤗 aplica este procesamiento es a través de campos añadidos al conjunto de datos, uno por cada diccionario devuelto por la función de preprocesamiento. +La manera en que la librería 🤗 Datasets aplica este procesamiento es a través de campos añadidos al conjunto de datos, uno por cada diccionario devuelto por la función de preprocesamiento. ```python out DatasetDict({ @@ -274,7 +277,7 @@ DatasetDict({ }) ``` -Hasta puedes usar multiprocesamiento cuando aplicas la función de preprocesamiento con `map()` pasando el argumento `num_proc`. Nosotros no usamos esta opción porque los Tokenizadores de la libreria 🤗 usa múltiples hilos de procesamiento para tokenizar rápidamente nuestros elementos, pero sino estas usando un tokenizador rápido respaldado por esta libreria, esta opción puede acelerar tu preprocesamiento. +Hasta puedes usar multiprocesamiento cuando aplicas la función de preprocesamiento con `map()` pasando el argumento `num_proc`. Nosotros no usamos esta opción porque los tokenizadores de la librería 🤗 Tokenizers usa múltiples hilos de procesamiento para tokenizar rápidamente nuestros elementos, pero sino estas usando un tokenizador rápido respaldado por esta librería, esta opción puede acelerar tu preprocesamiento. Nuestra función `tokenize_function` devuelve un diccionario con las llaves `input_ids`, `attention_mask`, y `token_type_ids`, así que esos tres campos son adicionados a todas las divisiones de nuestro conjunto de datos. Nótese que pudimos haber cambiado los campos existentes si nuestra función de preprocesamiento hubiese devuelto un valor nuevo para cualquiera de las llaves en el conjunto de datos al que le aplicamos `map()`. @@ -293,20 +296,24 @@ La función responsable de juntar los elementos dentro de un lote es llamada *fu {/if} -Para poner esto en práctica, tenemos que definir una función de cotejo que aplique la cantidad correcta de relleno a los elementos del conjunto de datos que queremos agrupar. Afortundamente, la libreria Transformers de 🤗 nos provee esta función mediante `DataCollatorWithPadding`. Esta recibe un tokenizador cuando la creas (para saber cual token de relleno se debe usar, y si el modelo espera el relleno a la izquierda o la derecha en las entradas) y hace todo lo que necesitas: +Para poner esto en práctica, tenemos que definir una función de cotejo que aplique la cantidad correcta de relleno a los elementos del conjunto de datos que queremos agrupar. Afortunadamente, la librería 🤗 Transformers nos provee esta función mediante `DataCollatorWithPadding`. Esta recibe un tokenizador cuando la creas (para saber cual token de relleno se debe usar, y si el modelo espera el relleno a la izquierda o la derecha en las entradas) y hace todo lo que necesitas: {#if fw === 'pt'} + ```py from transformers import DataCollatorWithPadding data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ``` + {:else} + ```py from transformers import DataCollatorWithPadding data_collator = DataCollatorWithPadding(tokenizer=tokenizer, return_tensors="tf") ``` + {/if} Para probar este nuevo juguete, tomemos algunos elementos de nuestro conjunto de datos de entrenamiento para agruparlos. Aquí, removemos las columnas `idx`, `sentence1`, and `sentence2` ya que éstas no se necesitan y contienen cadenas (y no podemos crear tensores con cadenas), miremos las longitudes de cada elemento en el lote. @@ -346,20 +353,19 @@ batch = data_collator(samples) 'labels': torch.Size([8])} ``` -Luce bién! Ahora que hemos convertido el texto crudo a lotes que nuestro modelo puede aceptar, estamos listos para ajustarlo! +¡Luce bien! Ahora que hemos convertido el texto crudo a lotes que nuestro modelo puede aceptar, estamos listos para ajustarlo! {/if} -✏️ **Inténtalo!** Reproduce el preprocesamiento en el conjunto de datos GLUE SST-2. Es un poco diferente ya que esta compuesto de oraciones individuales en lugar de pares, pero el resto de lo que hicimos deberia ser igual. Para un reto mayor, intenta escribir una función de preprocesamiento que trabaje con cualquiera de las tareas GLUE. +✏️ **¡Inténtalo!** Reproduce el preprocesamiento en el conjunto de datos GLUE SST-2. Es un poco diferente ya que esta compuesto de oraciones individuales en lugar de pares, pero el resto de lo que hicimos debería ser igual. Para un reto mayor, intenta escribir una función de preprocesamiento que trabaje con cualquiera de las tareas GLUE. {#if fw === 'tf'} -Ahora que tenemos nuestro conjunto de datos y el cotejador de datos, necesitamos juntarlos. Nosotros podriamos cargar lotes de datos y cotejarlos, pero eso sería mucho trabajo, y probablemente no muy eficiente. En cambio, existe un método que ofrece una solución eficiente para este problema: `to_tf_dataset()`. Este envuelve un `tf.data.Dataset` alrededor de tu conjunto de datos, con una función opcional de cotejo. `tf.data.Dataset` es un formato nativo de TensorFlow que Keras puede usar con el `model.fit()`, así este método convierte inmediatamente un conjunto de datos 🤗 a un formato que viene listo para entrenamiento. Veámoslo en acción con nuestro conjunto de datos. - +Ahora que tenemos nuestro conjunto de datos y el cotejador de datos, necesitamos juntarlos. Nosotros podríamos cargar lotes de datos y cotejarlos, pero eso sería mucho trabajo, y probablemente no muy eficiente. En cambio, existe un método que ofrece una solución eficiente para este problema: `to_tf_dataset()`. Este envuelve un `tf.data.Dataset` alrededor de tu conjunto de datos, con una función opcional de cotejo. `tf.data.Dataset` es un formato nativo de TensorFlow que Keras puede usar con el `model.fit()`, así este método convierte inmediatamente un conjunto de datos 🤗 a un formato que viene listo para entrenamiento. Veámoslo en acción con nuestro conjunto de datos. ```py tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( @@ -379,6 +385,6 @@ tf_validation_dataset = tokenized_datasets["validation"].to_tf_dataset( ) ``` -Y eso es todo! Ahora podemos usar esos conjuntos de datos en nuestra próxima clase, donde el entrenamiento será mas sencillo después de todo el trabajo de preprocesamiento de datos. +¡Y eso es todo! Ahora podemos usar esos conjuntos de datos en nuestra próxima clase, donde el entrenamiento será mas sencillo después de todo el trabajo de preprocesamiento de datos. {/if} diff --git a/chapters/es/chapter3/4.mdx b/chapters/es/chapter3/4.mdx index c0749b535..2081aa71e 100644 --- a/chapters/es/chapter3/4.mdx +++ b/chapters/es/chapter3/4.mdx @@ -5,7 +5,7 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/es/chapter3/section4.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/es/chapter3/section4.ipynb"}, -]} /> + ]} /> @@ -30,7 +30,7 @@ data_collator = DataCollatorWithPadding(tokenizer=tokenizer) ### Prepárate para el entrenamiento -Antes de escribir nuestro bucle de entrenamiento, necesitaremos definir algunos objetos. Los primeros son los dataloaders que usaremos para iterar sobre lotes. Pero antes de que podamos definir esos dataloaders, necesitamos aplicar un poquito de preprocesamiento a nuestro `tokenized_datasets`, para encargarnos de algunas cosas que el `Trainer` hizo por nosotros de manera automática. Específicamente, necesitamos: +Antes de escribir nuestro bucle de entrenamiento, necesitaremos definir algunos objetos. Los primeros son los `dataloaders` (literalmente, "cargadores de datos") que usaremos para iterar sobre lotes. Pero antes de que podamos definir esos `dataloaders`, necesitamos aplicar un poquito de preprocesamiento a nuestro `tokenized_datasets`, para encargarnos de algunas cosas que el `Trainer` hizo por nosotros de manera automática. Específicamente, necesitamos: - Remover las columnas correspondientes a valores que el model no espera (como las columnas `sentence1` y `sentence2`). - Renombrar la columna `label` con `labels` (porque el modelo espera el argumento llamado `labels`). @@ -51,7 +51,7 @@ Ahora podemos verificar que el resultado solo tiene columnas que nuestro modelo ["attention_mask", "input_ids", "labels", "token_type_ids"] ``` -Ahora que esto esta hecho, es fácil definir nuestros dataloaders: +Ahora que esto esta hecho, es fácil definir nuestros `dataloaders`: ```py from torch.utils.data import DataLoader @@ -100,7 +100,7 @@ print(outputs.loss, outputs.logits.shape) tensor(0.5441, grad_fn=) torch.Size([8, 2]) ``` -Todos los modelos Transformers 🤗 van a retornar la pérdida cuando se pasan los `labels`, y también obtenemos los logits (dos por cada entrada en nuestro lote, asi que es un tensor de tamaño 8 x 2). +Todos los modelos 🤗 Transformers van a retornar la pérdida cuando se pasan los `labels`, y también obtenemos los logits (dos por cada entrada en nuestro lote, asi que es un tensor de tamaño 8 x 2). Estamos casi listos para escribir nuestro bucle de entrenamiento! Nos están faltando dos cosas: un optimizador y un programador de la tasa de aprendizaje. Ya que estamos tratando de replicar a mano lo que el `Trainer` estaba haciendo, usaremos los mismos valores por defecto. El optimizador usado por el `Trainer` es `AdamW`, que es el mismo que Adam, pero con un cambio para la regularización de decremento de los pesos (ver ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) por Ilya Loshchilov y Frank Hutter): @@ -146,7 +146,7 @@ device device(type='cuda') ``` -Ya estamos listos para entrenar! Para tener una idea de cuando el entrenamiento va a terminar, adicionamos una barra de progreso sobre el número de pasos de entrenamiento, usando la libreria `tqdm`: +Ya estamos listos para entrenar! Para tener una idea de cuando el entrenamiento va a terminar, adicionamos una barra de progreso sobre el número de pasos de entrenamiento, usando la librería `tqdm`: ```py from tqdm.auto import tqdm @@ -171,7 +171,7 @@ Puedes ver que la parte central del bucle de entrenamiento luce bastante como el ### El bucle de evaluación -Como lo hicimos anteriormente, usaremos una métrica ofrecida por la libreria 🤗 Evaluate. Ya hemos visto el método `metric.compute()`, pero de hecho las métricas se pueden acumular sobre los lotes a medida que avanzamos en el bucle de predicción con el método `add_batch()`. Una vez que hemos acumulado todos los lotes, podemos obtener el resultado final con `metric.compute()`. Aquí se muestra como se puede implementar en un bucle de evaluación: +Como lo hicimos anteriormente, usaremos una métrica ofrecida por la librería 🤗 Evaluate. Ya hemos visto el método `metric.compute()`, pero de hecho las métricas se pueden acumular sobre los lotes a medida que avanzamos en el bucle de predicción con el método `add_batch()`. Una vez que hemos acumulado todos los lotes, podemos obtener el resultado final con `metric.compute()`. Aquí se muestra como se puede implementar en un bucle de evaluación: ```py import evaluate @@ -206,7 +206,7 @@ De nuevo, tus resultados serán un tanto diferente debido a la inicialización a -El bucle de entrenamiento que definimos anteriormente trabaja bien en un solo CPU o GPU. Pero usando la libreria [Accelerate 🤗](https://github.com/huggingface/accelerate), con solo pocos ajustes podemos habilitar el entrenamiento distribuido en múltiples GPUs o CPUs. Comenzando con la creación de los dataloaders de entrenamiento y validación, aquí se muestra como luce nuestro bucle de entrenamiento: +El bucle de entrenamiento que definimos anteriormente trabaja bien en un solo CPU o GPU. Pero usando la librería [Accelerate 🤗](https://github.com/huggingface/accelerate), con solo pocos ajustes podemos habilitar el entrenamiento distribuido en múltiples GPUs o CPUs. Comenzando con la creación de los `dataloaders` de entrenamiento y validación, aquí se muestra como luce nuestro bucle de entrenamiento: ```py from transformers import AdamW, AutoModelForSequenceClassification, get_scheduler @@ -242,7 +242,7 @@ for epoch in range(num_epochs): progress_bar.update(1) ``` -Y aqui están los cambios: +Y aquí están los cambios: ```diff + from accelerate import Accelerator @@ -286,15 +286,17 @@ Y aqui están los cambios: progress_bar.update(1) ``` -La primera línea a agregarse es la línea del import. La segunda línea crea un objeto `Accelerator` que revisa el ambiente e inicializa la configuración distribuida apropiada. La libreria Accelerate 🤗 se encarga de asignarte el dispositivo, para que puedas remover las líneas que ponen el modelo en el dispositivo (o si prefieres, cámbialas para usar el `accelerator.device` en lugar de `device`). +La primera línea a agregarse es la línea del import. La segunda línea crea un objeto `Accelerator` que revisa el ambiente e inicializa la configuración distribuida apropiada. La librería Accelerate 🤗 se encarga de asignarte el dispositivo, para que puedas remover las líneas que ponen el modelo en el dispositivo (o si prefieres, cámbialas para usar el `accelerator.device` en lugar de `device`). -Ahora la mayor parte del trabajo se hace en la línea que envia los dataloaders, el modelo y el optimizador al `accelerator.prepare()`. Este va a envolver esos objetos en el contenedor apropiado para asegurarse que tu entrenamiento distribuido funcione como se espera. Los cambios que quedan son remover la línea que coloca el lote en el `device` (de nuevo, si deseas dejarlo asi bastaría con cambiarlo para que use el `accelerator.device`) y reemplazar `loss.backward()` con `accelerator.backward(loss)`. +Ahora la mayor parte del trabajo se hace en la línea que envía los `dataloaders`, el modelo y el optimizador al `accelerator.prepare()`. Este va a envolver esos objetos en el contenedor apropiado para asegurarse que tu entrenamiento distribuido funcione como se espera. Los cambios que quedan son remover la línea que coloca el lote en el `device` (de nuevo, si deseas dejarlo asi bastaría con cambiarlo para que use el `accelerator.device`) y reemplazar `loss.backward()` con `accelerator.backward(loss)`. -⚠️ Para obtener el beneficio de la aceleración ofrecida por los TPUs de la nube, recomendamos rellenar las muestras hasta una longitud fija con los argumentos `padding="max_length"` y `max_length` del tokenizador. + ⚠️ Para obtener el beneficio de la aceleración ofrecida por los TPUs de la + nube, recomendamos rellenar las muestras hasta una longitud fija con los + argumentos `padding="max_length"` y `max_length` del tokenizador. -Si deseas copiarlo y pegarlo para probar, así es como luce el bucle completo de entrenamiento con Accelerate 🤗: +Si deseas copiarlo y pegarlo para probar, así es como luce el bucle completo de entrenamiento con 🤗 Accelerate: ```py from accelerate import Accelerator @@ -334,6 +336,7 @@ for epoch in range(num_epochs): ``` Colocando esto en un script `train.py` permitirá que el mismo sea ejecutable en cualquier configuración distribuida. Para probarlo en tu configuración distribuida, ejecuta el siguiente comando: + ```bash accelerate config ``` @@ -354,4 +357,4 @@ from accelerate import notebook_launcher notebook_launcher(training_function) ``` -Puedes encontrar más ejemplos en el [repositorio Accelerate 🤗](https://github.com/huggingface/accelerate/tree/main/examples). +Puedes encontrar más ejemplos en el [repositorio 🤗 Accelerate](https://github.com/huggingface/accelerate/tree/main/examples). diff --git a/chapters/es/chapter5/4.mdx b/chapters/es/chapter5/4.mdx index 344fb0545..f04f63d5c 100644 --- a/chapters/es/chapter5/4.mdx +++ b/chapters/es/chapter5/4.mdx @@ -5,9 +5,9 @@ notebooks={[ {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter5/section4.ipynb"}, {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter5/section4.ipynb"}, -]} /> + ]} /> -Hoy en día es común que tengas que trabajar con dataset de varios GB, especialmente si planeas pre-entrenar un transformador como BERT o GPT-2 desde ceros. En estos casos, _solamente cargar_ los datos puede ser un desafío. Por ejemplo, el corpus de WebText utilizado para preentrenar GPT-2 consiste de más de 8 millones de documentos y 40 GB de texto. ¡Cargarlo en la RAM de tu computador portatil le va a causar un paro cardiaco! +Hoy en día es común que tengas que trabajar con dataset de varios GB, especialmente si planeas pre-entrenar un transformador como BERT o GPT-2 desde ceros. En estos casos, _solamente cargar_ los datos puede ser un desafío. Por ejemplo, el corpus de WebText utilizado para preentrenar GPT-2 consiste de más de 8 millones de documentos y 40 GB de texto. ¡Cargarlo en la RAM de tu computador portátil le va a causar un paro cardíaco! Afortunadamente, 🤗 Datasets está diseñado para superar estas limitaciones: te libera de problemas de manejo de memoria al tratar los datasets como archivos _proyectados en memoria_ (_memory-mapped_) y de límites de almacenamiento al hacer _streaming_ de las entradas en un corpus. @@ -212,9 +212,9 @@ list(dataset_head) También podemos usar la función `IterableDataset.skip()` para crear conjuntos de entrenamiento y validación de un dataset ordenado aleatóriamente así: ```py -# Skip the first 1,000 examples and include the rest in the training set +# Salta las primeras 1000 muestras e incluye el resto en el conjunto de entrenamiento train_dataset = shuffled_dataset.skip(1000) -# Take the first 1,000 examples for the validation set +# Toma las primeras 1000 muestras para el conjunto de validación validation_dataset = shuffled_dataset.take(1000) ``` @@ -283,4 +283,3 @@ next(iter(pile_dataset["train"])) Ya tienes todas las herramientas para cargar y procesar datasets de todas las formas y tamaños, pero a menos que seas muy afortunado, llegará un punto en tu camino de PLN en el que tendrás que crear el dataset tu mismo para resolver tu problema particular. De esto hablaremos en la siguiente sección. -