{"id":652183,"date":"2025-10-28T23:23:29","date_gmt":"2025-10-28T22:23:29","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=pycharm&#038;p=652183"},"modified":"2025-10-28T23:23:37","modified_gmt":"2025-10-28T22:23:37","slug":"ajuste-e-implementacion-de-modelos-de-gpt-con-transformers-de-hugging-face","status":"publish","type":"pycharm","link":"https:\/\/blog.jetbrains.com\/es\/pycharm\/2025\/10\/ajuste-e-implementacion-de-modelos-de-gpt-con-transformers-de-hugging-face\/","title":{"rendered":"Ajuste e implementaci\u00f3n de modelos de GPT con Transformers de Hugging Face"},"content":{"rendered":"<p>Actualmente, Hugging Face es un referente entre los investigadores y los entusiastas del aprendizaje autom\u00e1tico. Uno de sus mayores \u00e9xitos son los <a href=\"https:\/\/huggingface.co\/docs\/transformers\/en\/index\" target=\"_blank\" rel=\"noopener\">Transformers<\/a>, un marco de trabajo de definici\u00f3n de modelos para aprendizaje autom\u00e1tico en texto, visi\u00f3n artificial, audio y v\u00eddeo. Debido al amplio repositorio de modelos de aprendizaje autom\u00e1tico de \u00faltima generaci\u00f3n disponibles en <a href=\"https:\/\/huggingface.co\/models\" target=\"_blank\" rel=\"noopener\">Hugging Face Hub<\/a> y a la compatibilidad de los Transformers con la mayor\u00eda de los marcos de trabajo de entrenamiento, se utiliza ampliamente para la inferencia y el entrenamiento de modelos.<\/p>\n<h2 class=\"wp-block-heading\">\u00bfPor qu\u00e9 queremos ajustar un modelo de IA?<\/h2>\n<p>El ajuste de los modelos de IA es fundamental para adaptar su rendimiento a tareas y conjuntos de datos espec\u00edficos, lo que les permite ser m\u00e1s precisos y eficientes en comparaci\u00f3n con el uso de un modelo generalista. Al adaptar un modelo entrenado previamente, el ajuste no implica un entrenamiento desde cero, lo que ahorra tiempo y recursos. Tambi\u00e9n permite manejar mejor los formatos espec\u00edficos, los matices y los casos extremos dentro de un campo concreto, por lo que los resultados son m\u00e1s fiables y personalizados.<\/p>\n<p>En este art\u00edculo del blog, ajustaremos un modelo de GPT con razonamiento matem\u00e1tico para que maneje mejor las preguntas sobre matem\u00e1ticas.<\/p>\n<h2 class=\"wp-block-heading\">Uso de modelos de Hugging Face<\/h2>\n<p>Si usamos PyCharm, podemos explorar y a\u00f1adir f\u00e1cilmente cualquier modelo de Hugging Face. En un nuevo archivo de Python, desde el men\u00fa <em>Code<\/em> de la parte superior, seleccione <em>Insert HF Model<\/em>.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594074\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-40.png\" alt=\"Uso de modelos de Hugging Face\" width=\"946\" height=\"1070\" \/><\/figure>\n<p>En el men\u00fa que se abre, ver\u00e1 los modelos por categor\u00eda o podr\u00e1 escribir en la barra de b\u00fasqueda situada en la parte superior. Al seleccionar un modelo, ver\u00e1 su descripci\u00f3n a la derecha.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594085\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-41.png\" alt=\"Exploraci\u00f3n de modelos de Hugging Face\" width=\"1600\" height=\"923\" \/><\/figure>\n<p>Al hacer clic en <em>Use Model<\/em>, ver\u00e1 que se a\u00f1ade un fragmento de c\u00f3digo al archivo. \u00a1Ya lo tiene! Listo para empezar a usar el modelo de Hugging Face.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594096\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-42.png\" alt=\"Uso de modelos de Hugging Face en PyCharm\" width=\"1600\" height=\"312\" \/><\/figure>\n<h2 class=\"wp-block-heading\">Modelos de GPT (Generative Pre-Trained Transformer)<\/h2>\n<p>Los modelos de GPT son muy populares en <a href=\"https:\/\/huggingface.co\/models\" target=\"_blank\" rel=\"noopener\">Hugging Face Hub<\/a>, pero \u00bfqu\u00e9 son? Los GPT son modelos entrenados que entienden el lenguaje natural y generan texto de alta calidad. Se utilizan principalmente en tareas relacionadas con los textos, la respuesta a preguntas, la similitud sem\u00e1ntica y la clasificaci\u00f3n de documentos. El ejemplo m\u00e1s conocido es <a href=\"https:\/\/openai.com\/index\/chatgpt\/\" target=\"_blank\" rel=\"noopener\">ChatGPT, creado por OpenAI<\/a>.<\/p>\n<p>Hay muchos modelos de GPT de OpenAI disponibles en <a href=\"https:\/\/huggingface.co\/models\" target=\"_blank\" rel=\"noopener\">Hugging Face Hub<\/a> y aprenderemos a utilizarlos con los Transformers, ajustarlos con nuestros propios datos e implementarlos en una aplicaci\u00f3n.<\/p>\n<h2 class=\"wp-block-heading\">Ventajas de utilizar Transformers<\/h2>\n<p>Los Transformers, junto con otras herramientas proporcionadas por Hugging Face, ofrecen herramientas de alto nivel para ajustar cualquier modelo sofisticado de aprendizaje profundo. En lugar de exigirle que comprenda completamente la arquitectura y el m\u00e9todo de tokenizaci\u00f3n de un modelo determinado, estas herramientas ayudan a que los modelos sean \u00abplug and play\u00bb con cualquier dato de entrenamiento compatible, adem\u00e1s de que permiten personalizar mucho la tokenizaci\u00f3n y el entrenamiento.<\/p>\n<h2 class=\"wp-block-heading\">Transformers en acci\u00f3n<\/h2>\n<p>Para ver m\u00e1s de cerca c\u00f3mo funcionan los Transformers, veamos c\u00f3mo podemos utilizarlos para interactuar con un modelo de GPT.<\/p>\n<h3 class=\"wp-block-heading\">Inferencia utilizando un modelo entrenado previamente con un proceso<\/h3>\n<p>Tras seleccionar y a\u00f1adir el modelo OpenAI GPT-2 al c\u00f3digo, esto es lo que obtenemos:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from transformers import pipeline\n\n\npipe = pipeline(\"text-generation\", model=\"openai-community\/gpt2\")<\/pre>\n<p>Antes de poder utilizarlo, debemos hacer algunos ajustes. En primer lugar, debemos instalar un marco de trabajo de aprendizaje autom\u00e1tico. En este ejemplo, hemos elegido <a href=\"https:\/\/pytorch.org\/get-started\/locally\/\" target=\"_blank\" rel=\"noopener\">PyTorch<\/a>. Se puede instalar f\u00e1cilmente a trav\u00e9s de la ventana <em>Python Packages<\/em> en PyCharm.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594107\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-43.png\" alt=\"Instalaci\u00f3n de PyTorch en PyCharm\" width=\"920\" height=\"654\" \/><\/figure>\n<p>A continuaci\u00f3n, debemos instalar los Transformers con la opci\u00f3n `torch`. Para ello, utilice el terminal: \u00e1bralo con el bot\u00f3n de la izquierda o utilice la tecla de acceso r\u00e1pido <em>\u2325 F12<\/em> (macOS) o <em>Alt + F12<\/em> (Windows).<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594118\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-44.png\" alt=\"Instalaci\u00f3n de Transformers en el terminal de PyCharm\" width=\"838\" height=\"502\" \/><\/figure>\n<p>En el terminal, dado que estamos con uv, utilizamos los siguientes comandos para a\u00f1adirlo como dependencia e instalarlo:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">uv add \u201ctransformers[torch]\u201d\nuv sync<\/pre>\n<p>Si usa pip:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">pip install \u201ctransformers[torch]\u201d<\/pre>\n<p>Tambi\u00e9n instalaremos un par de bibliotecas m\u00e1s que necesitaremos m\u00e1s adelante, como python-dotenv, datasets<em>, <\/em>notebook e ipywidgets<em>. <\/em>Puede utilizar cualquiera de los m\u00e9todos anteriores para instalarlas.<br \/>Despu\u00e9s, lo mejor ser\u00eda a\u00f1adir un dispositivo GPU para acelerar el modelo. Dependiendo de lo que haya en la m\u00e1quina, se puede a\u00f1adir configurando el par\u00e1metro del dispositivo en el proceso<em>. <\/em>Como estoy usando una m\u00e1quina Mac M2, puedo configurar <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">device=\"mps\"<\/code> as\u00ed:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">pipe = pipeline(\"text-generation\", model=\"openai-community\/gpt2\", device=\"mps\")<\/pre>\n<p>Si tiene una GPU CUDA, tambi\u00e9n puede configurar <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">device=\"cuda\"<\/code>.<\/p>\n<p>Ahora que hemos configurado el canal, vamos a probarlo con una petici\u00f3n sencilla:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from transformers import pipeline\n\n\npipe = pipeline(\"text-generation\", model=\"openai-community\/gpt2\", device=\"mps\")\n\n\nprint(pipe(\"A rectangle has a perimeter of 20 cm. If the length is 6 cm, what is the width?\", max_new_tokens=200))<\/pre>\n<p>Ejecute el script con el bot\u00f3n <em>Run<\/em> (<img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/AD_4nXf6ZDm7vSGyFlO0DzXegK6WP9JxsStUiJA-bkRZ0mwPsUsmn8M70emV5Sr8f17-fEK6z9V1EQKWEm3RPHdT8n8uqG18faVmQn5y09psVInQLU0CZQKXAEg2q7m7AOsh4hPU7G8gcQ.png\" width=\"30\" height=\"23\" \/>) situado en la parte superior:<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594129\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-45.png\" alt=\"Ejecuci\u00f3n del script en PyCharm\" width=\"1050\" height=\"282\" \/><\/figure>\n<p>El resultado se parecer\u00e1 a esto:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[{'generated_text': 'A rectangle has a perimeter of 20 cm. If the length is 6 cm, what is the width?nnA rectangle has a perimeter of 20 cm. If the length is 6 cm, what is the width? A rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width? A rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width? A rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width?nnA rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width? A rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width? A rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width? A rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width?nnA rectangle has a perimeter of 20 cm. If the width is 6 cm, what is the width? A rectangle has a perimeter'}]<\/pre>\n<p>Aqu\u00ed no hay demasiado razonamiento, sino palabras sin mucho sentido.\u00a0<\/p>\n<p>Tambi\u00e9n es posible que aparezca esta advertencia:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">Setting `pad_token_id` to `eos_token_id`:50256 for open-end generation.<\/pre>\n<p>Esta es la configuraci\u00f3n predeterminada. Tambi\u00e9n puede a\u00f1adirla de forma manual como se muestra a continuaci\u00f3n para que esta advertencia desaparezca, pero ahora mismo no es algo que deba preocuparnos.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">print(pipe(\"A rectangle has a perimeter of 20 cm. If the length is 6 cm, what is the width?\", max_new_tokens=200, pad_token_id=pipe.tokenizer.eos_token_id))<\/pre>\n<p>Ahora que hemos visto c\u00f3mo se comporta GPT-2 sin configuraciones adicionales, veamos si podemos mejorar su razonamiento matem\u00e1tico con algunos ajustes.<\/p>\n<h3 class=\"wp-block-heading\">Carga y preparaci\u00f3n de un conjunto de datos desde Hugging Face Hub<\/h3>\n<p>Antes de trabajar con el modelo de GPT, primero necesitamos datos de entrenamiento. Veamos c\u00f3mo conseguir un conjunto de datos desde Hugging Face Hub.<\/p>\n<p>Si a\u00fan no lo ha hecho, reg\u00edstrese en Hugging Face y <a href=\"https:\/\/huggingface.co\/docs\/hub\/security-tokens#user-access-tokens\" target=\"_blank\" rel=\"noopener\">cree un token de acceso<\/a>. De momento, solo necesitamos un token `read`. Guarde el token as\u00ed en un archivo `.env`:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">HF_TOKEN=your-hugging-face-access-token<\/pre>\n<p>Utilizaremos este <a href=\"https:\/\/huggingface.co\/datasets\/Cheukting\/math-meta-reasoning-cleaned\" target=\"_blank\" rel=\"noopener\">conjunto de datos de razonamiento matem\u00e1tico<\/a>, que contiene texto que describe algunos razonamientos matem\u00e1ticos. Ajustaremos nuestro modelo GPT con este conjunto de datos para que pueda resolver problemas matem\u00e1ticos de forma m\u00e1s eficaz.<\/p>\n<p>Vamos a crear un nuevo notebook de Jupyter, que utilizaremos para el proceso de ajuste, ya que nos permite ejecutar diferentes fragmentos de c\u00f3digo uno por uno y supervisar el progreso.<\/p>\n<p>En la primera celda, utilizamos este script para cargar el conjunto de datos desde Hugging Face Hub:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from datasets import load_dataset\nfrom dotenv import load_dotenv\nimport os\n\n\nload_dotenv()\ndataset = load_dataset(\"Cheukting\/math-meta-reasoning-cleaned\", token=os.getenv(\"HF_TOKEN\"))\ndataset<\/pre>\n<p>Ejecute esta celda (puede tardar un poco, seg\u00fan la velocidad de su conexi\u00f3n a Internet), que descargar\u00e1 el conjunto de datos. Cuando haya terminado, podremos ver el resultado:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DatasetDict({\n    train: Dataset({\n        features: ['id', 'text', 'token_count'],\n        num_rows: 987485\n    })\n})\n<\/pre>\n<p>Si tiene curiosidad y quiere echar un vistazo a los datos, puede hacerlo en PyCharm. Abra la ventana <em>Jupyter Variables<\/em> con el bot\u00f3n de la derecha:<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594140\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-46.png\" alt=\"Apertura de Jupyter Variables en PyCharm\" width=\"1052\" height=\"740\" \/><\/figure>\n<p>Expanda el <em>conjunto de datos<\/em> y ver\u00e1 la opci\u00f3n <em>View as DataFrame<\/em> junto a <em>dataset[\u2018train\u2019]<\/em>:<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594152\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-47.png\" alt=\"Jupyter Variables en PyCharm\" width=\"980\" height=\"882\" \/><\/figure>\n<p>Haga clic en este para ver los datos en la ventana de herramientas <em>Data View<\/em>:<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594163\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-48.png\" alt=\"Herramienta Data View en PyCharm\" width=\"980\" height=\"1102\" \/><\/figure>\n<p>A continuaci\u00f3n, tokenizaremos el texto del conjunto de datos:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from transformers import GPT2Tokenizer\n\n\ntokenizer = GPT2Tokenizer.from_pretrained(\"openai-community\/gpt2\")\ntokenizer.pad_token = tokenizer.eos_token\n\n\ndef tokenize_function(examples):\n   return tokenizer(examples['text'], truncation=True, padding='max_length', max_length=512)\n\n\ntokenized_datasets = dataset.map(tokenize_function, batched=True)<\/pre>\n<p>Aqu\u00ed utilizamos el tokenizador GPT-2 y configuramos el <code>pad_token<\/code> para que sea el <code>eos_token<\/code>, que es el token que indica el final de la l\u00ednea. A continuaci\u00f3n, tokenizaremos el texto con una funci\u00f3n. Es posible que la primera vez que lo ejecute tarde un poco, pero despu\u00e9s se almacenar\u00e1 en la cach\u00e9 y ser\u00e1 m\u00e1s r\u00e1pido si hay que volver a ejecutar la celda.<\/p>\n<p>El conjunto de datos tiene casi un mill\u00f3n de filas para el entrenamiento. Si tiene suficiente potencia de c\u00e1lculo para procesarlas todas, puede utilizarlas todas. Sin embargo, en esta demostraci\u00f3n estamos entrenando de forma local en un ordenador port\u00e1til, \u00a1as\u00ed que es mejor que utilice solo una peque\u00f1a parte!<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">tokenized_datasets_split = tokenized_datasets[\"train\"].shard(num_shards=100, index=0).train_test_split(test_size=0.2, shuffle=True)\ntokenized_datasets_split<\/pre>\n<p>Aqu\u00ed tomo solo el 1\u00a0% de los datos y, a continuaci\u00f3n, ejecuto <code>train_test_split<\/code> para dividir el conjunto de datos en dos:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DatasetDict({\n    train: Dataset({\n        features: ['id', 'text', 'token_count', 'input_ids', 'attention_mask'],\n        num_rows: 7900\n    })\n    test: Dataset({\n        features: ['id', 'text', 'token_count', 'input_ids', 'attention_mask'],\n        num_rows: 1975\n    })\n})\n<\/pre>\n<p>Ya estamos listos para ajustar el modelo GPT-2.<\/p>\n<h3 class=\"wp-block-heading\">Ajuste de un modelo de GPT<\/h3>\n<p>En la siguiente celda vac\u00eda, estableceremos los argumentos de entrenamiento:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from transformers import TrainingArguments\ntraining_args = TrainingArguments(\n   output_dir='.\/results',\n   num_train_epochs=5,\n   per_device_train_batch_size=8,\n   per_device_eval_batch_size=8,\n   warmup_steps=100,\n   weight_decay=0.01,\n   save_steps = 500,\n   logging_steps=100,\n   dataloader_pin_memory=False\n)<\/pre>\n<p>La mayor\u00eda de ellos son bastante est\u00e1ndar para ajustar un modelo, aunque, seg\u00fan la configuraci\u00f3n del ordenador, es posible que quiera modificar algunas cosas:<\/p>\n<ul>\n<li>Tama\u00f1o del lote: es importante encontrar el tama\u00f1o \u00f3ptimo del lote, ya que, cuanto mayor sea, m\u00e1s r\u00e1pido ser\u00e1 el entrenamiento. Sin embargo, hay un l\u00edmite en la cantidad de memoria disponible en la CPU o GPU, por lo que quiz\u00e1s haya un umbral m\u00e1ximo.<\/li>\n<li>\u00c9pocas: tener m\u00e1s \u00e9pocas hace que el entrenamiento tarde m\u00e1s, y puede decidir cu\u00e1ntas \u00e9pocas necesita.<\/li>\n<li>Puntos de guardado: los puntos de guardado determinan la frecuencia con la que se guardar\u00e1 un punto de control en el disco. Si el entrenamiento es lento y existe la posibilidad de que se detenga de forma inesperada, quiz\u00e1s quiera guardar con m\u00e1s frecuencia (establezca este valor en un valor m\u00e1s bajo).<\/li>\n<\/ul>\n<p>\u00a0Tras configurar los ajustes, a\u00f1adiremos al entrenador en la siguiente celda:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from transformers import Trainer, DataCollatorForLanguageModeling\n\n\nmodel = GPT2LMHeadModel.from_pretrained(\"openai-community\/gpt2\")\ndata_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)\n\n\ntrainer = Trainer(\n   model=model,\n   args=training_args,\n   train_dataset=tokenized_datasets_split['train'],\n   eval_dataset=tokenized_datasets_split['test'],\n   data_collator=data_collator,\n)\n\n\ntrainer.train(resume_from_checkpoint=False)<\/pre>\n<p>Hemos establecido `resume_from_checkpoint=False`, pero puede establecerlo en `True` para continuar desde el \u00faltimo punto de control si se interrumpe el entrenamiento.<\/p>\n<p>Una vez finalizado el entrenamiento, evaluaremos y guardaremos el modelo:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">trainer.evaluate(tokenized_datasets_split['test'])\ntrainer.save_model(\".\/trained_model\")<\/pre>\n<p>Ya podemos utilizar el modelo entrenado en el proceso. Volvamos a `model.py`, donde hemos utilizado un proceso con un modelo entrenado previamente:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">from transformers import pipeline\n\n\npipe = pipeline(\"text-generation\", model=\"openai-community\/gpt2\", device=\"mps\")\n\n\nprint(pipe(\"A rectangle has a perimeter of 20 cm. If the length is 6 cm, what is the width?\", max_new_tokens=200, pad_token_id=pipe.tokenizer.eos_token_id))<\/pre>\n<p>Ahora, cambiemos `model=\u201dopenai-community\/gpt2\u2033` to `model=\u201d.\/trained_model\u201d` y veamos qu\u00e9 obtenemos:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[{'generated_text': \"A rectangle has a perimeter of 20 cm. If the length is 6 cm, what is the width?nAlright, let me try to solve this problem as a student, and I'll let my thinking naturally fall into the common pitfall as described.nn---nn**Step 1: Attempting the Problem (falling into the pitfall)**nnWe have a rectangle with perimeter 20 cm. The length is 6 cm. We want the width.nnFirst, I need to find the area under the rectangle.nnLet\u2019s set ( A = 20 - 12 ), where ( A ) is the perimeter.nn**Area under a rectangle:**  n[nA = (20-12)^2 + ((-12)^2)^2 = 20^2 + 12^2 = 24n]nnSo, ( 24 = (20-12)^2 = 27 ).nnNow, I\u2019ll just divide both sides by 6 to find the area under the rectangle.n\"}]<\/pre>\n<p>Por desgracia, esto sigue sin resolver el problema, aunque s\u00ed que ha mostrado algunas f\u00f3rmulas matem\u00e1ticas y razonamientos que no se hab\u00edan utilizado antes. Si quiere, puede intentar ajustar un poco m\u00e1s el modelo con los datos que no hemos utilizado.<\/p>\n<p>En la siguiente secci\u00f3n, veremos c\u00f3mo podemos implementar un modelo ajustado en los puntos de conexi\u00f3n de la API con las herramientas proporcionadas por Hugging Face y FastAPI.<\/p>\n<h2 class=\"wp-block-heading\">Implementaci\u00f3n de un modelo ajustado<\/h2>\n<p>La forma m\u00e1s f\u00e1cil de implementar un modelo en un servidor de backend es utilizar FastAPI. Anteriormente, escrib\u00ed un <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2024\/09\/how-to-use-fastapi-for-machine-learning\/\">art\u00edculo en el blog<\/a> sobre la implementaci\u00f3n de un modelo de aprendizaje autom\u00e1tico con FastAPI. Aunque aqu\u00ed no entraremos en ese nivel de detalle, repasaremos c\u00f3mo implementar nuestro modelo ajustado.<\/p>\n<p>Con la ayuda de <a href=\"https:\/\/www.jetbrains.com\/junie\/\" target=\"_blank\" rel=\"noopener\">Junie<\/a>, hemos creado algunos scripts que puede consultar <a href=\"https:\/\/github.com\/Cheukting\/fine-tune-gpt2\/tree\/main\/app\" target=\"_blank\" rel=\"noopener\">aqu\u00ed<\/a>. Estos scripts nos permiten implementar un servidor de backend con puntos de conexi\u00f3n FastAPI.\u00a0<\/p>\n<p>Hay algunas dependencias nuevas que debemos a\u00f1adir:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">uv add fastapi pydantic uvicorn\nuv sync<\/pre>\n<p>Echemos un vistazo a algunos puntos interesantes de los scripts, en `main.py`:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Initialize FastAPI app\napp = FastAPI(\n   title=\"Text Generation API\",\n   description=\"API for generating text using a fine-tuned model\",\n   version=\"1.0.0\"\n)\n\n\n# Initialize the model pipeline\ntry:\n   pipe = pipeline(\"text-generation\", model=\"..\/trained_model\", device=\"mps\")\nexcept Exception as e:\n   # Fallback to CPU if MPS is not available\n   try:\n       pipe = pipeline(\"text-generation\", model=\"..\/trained_model\", device=\"cpu\")\n   except Exception as e:\n       print(f\"Error loading model: {e}\")\n       pipe = None<\/pre>\n<p>Tras arrancar la aplicaci\u00f3n, el script intentar\u00e1 cargar el modelo en un proceso. Si no hay ninguna GPU Metal disponible, recurrir\u00e1 al uso de la CPU. Si tiene una GPU CUDA en lugar de una GPU Metal, puede cambiar `mps` por `cuda`.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\"># Request model\nclass TextGenerationRequest(BaseModel):\n   prompt: str\n   max_new_tokens: int = 200\n  \n# Response model\nclass TextGenerationResponse(BaseModel):\n   generated_text: str<\/pre>\n<p>Se crean dos nuevas clases, heredadas de BaseModel de Pydantic.<\/p>\n<p>Tambi\u00e9n podemos inspeccionar nuestros puntos de conexi\u00f3n con la ventana de herramientas <em>Endpoints<\/em><em>. <\/em>Haga clic en el globo situado junto a `app = FastAPI` en la l\u00ednea 11 y seleccione <em>Show All Endpoints<\/em>.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594174\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-49.png\" alt=\"Mostrar todos los puntos de conexi\u00f3n en PyCharm\" width=\"1600\" height=\"833\" \/><\/figure>\n<p>Tenemos tres puntos de conexi\u00f3n. Dado que el punto de conexi\u00f3n ra\u00edz es solo un mensaje de bienvenida, nos centraremos en los otros dos.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@app.post(\"\/generate\", response_model=TextGenerationResponse)\nasync def generate_text(request: TextGenerationRequest):\n   \"\"\"\n   Generate text based on the provided prompt.\n  \n   Args:\n       request: TextGenerationRequest containing the prompt and generation parameters\n      \n   Returns:\n       TextGenerationResponse with the generated text\n   \"\"\"\n   if pipe is None:\n       raise HTTPException(status_code=500, detail=\"Model not loaded properly\")\n  \n   try:\n       result = pipe(\n           request.prompt,\n           max_new_tokens=request.max_new_tokens,\n           pad_token_id=pipe.tokenizer.eos_token_id\n       )\n      \n       # Extract the generated text from the result\n       generated_text = result[0]['generated_text']\n      \n       return TextGenerationResponse(generated_text=generated_text)\n   except Exception as e:\n       raise HTTPException(status_code=500, detail=f\"Error generating text: {str(e)}\")\n<\/pre>\n<p>El punto de conexi\u00f3n `\/generate` recopila la petici\u00f3n y genera el texto de respuesta con el modelo.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@app.get(\"\/health\")\nasync def health_check():\n   \"\"\"Check if the API and model are working properly.\"\"\"\n   if pipe is None:\n       raise HTTPException(status_code=500, detail=\"Model not loaded\")\n   return {\"status\": \"healthy\", \"model_loaded\": True}<\/pre>\n<p>El punto de conexi\u00f3n `\/health` comprueba si el modelo se ha cargado correctamente. Esto puede resultar \u00fatil si la aplicaci\u00f3n del lado del cliente necesita realizar una comprobaci\u00f3n antes de habilitar el otro punto de conexi\u00f3n en su interfaz de usuario.<\/p>\n<p>En `run.py`, utilizamos <a href=\"https:\/\/www.uvicorn.org\/\" target=\"_blank\" rel=\"noopener\">uvicorn<\/a> para ejecutar el servidor:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import uvicorn\n\n\nif __name__ == \"__main__\":\n   uvicorn.run(\"main:app\", host=\"0.0.0.0\", port=8000, reload=True)<\/pre>\n<p>Al ejecutar este script, el servidor se iniciar\u00e1 en <a href=\"http:\/\/0.0.0.0:8000\/\" target=\"_blank\" rel=\"noopener\">http:\/\/0.0.0.0:8000\/<\/a>.<\/p>\n<p>Una vez que hayamos iniciado el servidor, podemos ir a <a href=\"http:\/\/0.0.0.0:8000\/docs\" target=\"_blank\" rel=\"noopener\">http:\/\/0.0.0.0:8000\/docs<\/a> para probar los puntos de conexi\u00f3n.\u00a0<\/p>\n<h2 class=\"wp-block-heading\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/AD_4nXf6PXwz_Vz7VEQoyZs20NJ9TsO36oWJPf0w4iMjwHZ_EBP1Pk9c_8aWR2ybGE-wsmArM1zAQl1s8jHEr09I0g1A3boGD1Kt4i4CemufHZTHnATjIWrJ8x2ZUYg4Q7E4b3tc2XDmmg.png\" width=\"624\" height=\"269\" \/><\/h2>\n<p>Podemos probarlo con el punto de conexi\u00f3n `\/generate`:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"prompt\": \"5 people give each other a present. How many presents are given altogether?\",\n  \"max_new_tokens\": 300\n}<\/pre>\n<p>Esta es la respuesta que obtenemos:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"generated_text\": \"5 people give each other a present. How many presents are given altogether?nAlright, let's try to solve the problem:nn**Problem**  n1. Each person gives each other a present. How many presents are given altogether?n2. How many \"gift\" are given altogether?nn**Common pitfall**  nAssuming that each present is a \"gift\" without considering the implications of the original condition.nn---nn### Step 1: Attempting the problem (falling into the pitfall)nnOkay, so I have two people giving each other a present, and I want to know how many are present. I remember that there are three types of gifts\u2014gifts, gins, and ginses.nnLet me try to count how many of these:nn- Gifts: Let\u2019s say there are three people giving each other a present.n- Gins: Let\u2019s say there are three people giving each other a present.n- Ginses: Let\u2019s say there are three people giving each other a present.nnSo, total gins and ginses would be:nn- Gins: ( 2 times 3 = 1 ), ( 2 times 1 = 2 ), ( 1 times 1 = 1 ), ( 1 times 2 = 2 ), so ( 2 times 3 = 4 ).n- Ginses: ( 2 times 3 = 6 ), (\"\n}\n<\/pre>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-594185\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/08\/image-50.png\" alt=\"\" width=\"1600\" height=\"873\" \/><\/figure>\n<p>An\u00edmese a probar con otras peticiones.<\/p>\n<h2 class=\"wp-block-heading\">Conclusi\u00f3n y pr\u00f3ximos pasos<\/h2>\n<p>Ahora que ha ajustado con \u00e9xito un modelo de LLM como GPT-2 con un conjunto de datos de razonamiento matem\u00e1tico y lo ha implementado con FastAPI, puede ajustar muchos m\u00e1s LLM de c\u00f3digo abierto disponibles en Hugging Face Hub. Puede experimentar con el ajuste de otros modelos de LLM con los datos de c\u00f3digo abierto que hay all\u00ed o con sus propios conjuntos de datos. Si lo desea (y la licencia del modelo original lo permite), tambi\u00e9n puede cargar su modelo ajustado en Hugging Face Hub. Consulte la <a href=\"https:\/\/huggingface.co\/docs\/transformers\/v4.53.3\/en\/main_classes\/trainer#transformers.Trainer.push_to_hub\" target=\"_blank\" rel=\"noopener\">documentaci\u00f3n<\/a> para saber c\u00f3mo hacerlo.<\/p>\n<p>Un \u00faltimo apunte sobre el uso o el ajuste de modelos con recursos de Hugging Face Hub: aseg\u00farese de consultar las licencias de los modelos o conjuntos de datos que utilice para entender cu\u00e1les son las condiciones de trabajo con dichos recursos. \u00bfSe permite su uso con fines comerciales? \u00bfEs necesario citar los recursos utilizados?<\/p>\n<p>En art\u00edculos del blog posteriores, seguiremos explorando m\u00e1s ejemplos de c\u00f3digo relacionados con Python, la IA, el aprendizaje autom\u00e1tico y la visualizaci\u00f3n de datos.<\/p>\n<p>En mi opini\u00f3n, <a href=\"https:\/\/www.jetbrains.com\/pycharm\/\" target=\"_blank\" rel=\"noopener\">PyCharm<\/a> ofrece la mejor compatibilidad de su clase con Python, lo que garantiza tanto la velocidad como la precisi\u00f3n. Aproveche las ventajas de la finalizaci\u00f3n de c\u00f3digo m\u00e1s inteligente, las comprobaciones de cumplimiento de PEP 8, las refactorizaciones inteligentes y muchas inspecciones para satisfacer todas sus necesidades de codificaci\u00f3n. Como se muestra en este art\u00edculo del blog, PyCharm ofrece integraci\u00f3n con Hugging Face Hub, lo que le permite explorar y utilizar modelos sin salir del IDE. Esto lo hace adecuado para muchos proyectos de IA y de ajuste de LLM.<\/p>\n<div class=\"buttons\">\n<div class=\"buttons__row\"><a class=\"btn\" href=\"https:\/\/www.jetbrains.com\/pycharm\/\" target=\"\" rel=\"noopener\">Descargue PyCharm ahora<\/a><\/div>\n<\/div>\n\n\n<p>A<em>rt\u00edculo original en ingl\u00e9s de:<\/em><\/p>\n\n\n    <div class=\"about-author \">\n        <div class=\"about-author__box\">\n            <div class=\"row\">\n                <div class=\"about-author__box-img\">\n                    <img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/01\/CheukTingHo-Kimono-e1738750639162-200x200.jpg\" width=\"200\" height=\"200\" alt=\"Cheuk Ting Ho\" loading=\"lazy\"  class=\"avatar avatar-200 wp-user-avatar wp-user-avatar-200 photo avatar-default\">\n                <\/div>\n                <div class=\"about-author__box-text\">\n                                            <h4>Cheuk Ting Ho<\/h4>\n                                                        <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n","protected":false},"author":1086,"featured_media":653849,"comment_status":"closed","ping_status":"closed","template":"","categories":[952,1401],"tags":[8900,8428,3252],"cross-post-tag":[8851],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/pycharm\/652183"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/pycharm"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/types\/pycharm"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/users\/1086"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/comments?post=652183"}],"version-history":[{"count":2,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/pycharm\/652183\/revisions"}],"predecessor-version":[{"id":653861,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/pycharm\/652183\/revisions\/653861"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media\/653849"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media?parent=652183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/categories?post=652183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/tags?post=652183"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/cross-post-tag?post=652183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}