{"id":649021,"date":"2025-10-16T09:47:22","date_gmt":"2025-10-16T08:47:22","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=pycharm&#038;p=649021"},"modified":"2025-10-16T09:47:28","modified_gmt":"2025-10-16T08:47:28","slug":"affiner-et-deployer-des-modeles-gpt-avec-hugging-face-transformers","status":"publish","type":"pycharm","link":"https:\/\/blog.jetbrains.com\/fr\/pycharm\/2025\/10\/affiner-et-deployer-des-modeles-gpt-avec-hugging-face-transformers\/","title":{"rendered":"Affiner et d\u00e9ployer des mod\u00e8les GPT avec Hugging Face Transformers"},"content":{"rendered":"<p>Hugging Face est devenu une r\u00e9f\u00e9rence aussi bien pour les chercheurs en machine learning que pour les amateurs. L&#8217;un de leurs plus grands succ\u00e8s est <a href=\"https:\/\/huggingface.co\/docs\/transformers\/en\/index\" target=\"_blank\" rel=\"noopener\">Transformers<\/a>, un framework de d\u00e9finition de mod\u00e8les pour le machine learning, que ce soit pour le texte, la vision par ordinateur, l&#8217;audio ou la vid\u00e9o. En raison du vaste r\u00e9f\u00e9rentiel de mod\u00e8les de machine learning de pointe disponibles sur <a href=\"https:\/\/huggingface.co\/models\" target=\"_blank\" rel=\"noopener\">Hugging Face Hub<\/a> et de la compatibilit\u00e9 de Transformers avec la majorit\u00e9 des frameworks d&#8217;entra\u00eenement, il est largement utilis\u00e9 pour l&#8217;inf\u00e9rence et l&#8217;entra\u00eenement de mod\u00e8les.<\/p>\n<h2 class=\"wp-block-heading\">Pourquoi ajuster un mod\u00e8le d&#8217;IA ?<\/h2>\n<p>L&#8217;ajustement des mod\u00e8les d&#8217;IA est essentiel pour adapter leurs performances \u00e0 des t\u00e2ches et \u00e0 des ensembles de donn\u00e9es sp\u00e9cifiques, afin de les rendre plus pr\u00e9cis et efficaces par rapport \u00e0 un mod\u00e8le \u00e0 usage g\u00e9n\u00e9ral. En adaptant un mod\u00e8le pr\u00e9-entra\u00een\u00e9, l&#8217;ajustement r\u00e9duit la n\u00e9cessit\u00e9 de proc\u00e9der \u00e0 un entra\u00eenement \u00e0 partir de z\u00e9ro, ce qui permet d&#8217;\u00e9conomiser du temps et des ressources. Il permet \u00e9galement d&#8217;am\u00e9liorer le traitement de formats sp\u00e9cifiques, de nuances et de cas atypiques dans un domaine donn\u00e9, ce qui donne des r\u00e9sultats plus fiables et mieux adapt\u00e9s.<\/p>\n<p>Dans cet article, nous allons optimiser un mod\u00e8le GPT avec un raisonnement math\u00e9matique afin qu&#8217;il puisse mieux r\u00e9pondre aux questions du domaine des math\u00e9matiques.<\/p>\n<h2 class=\"wp-block-heading\">Utiliser des mod\u00e8les de Hugging Face<\/h2>\n<p>Lorsque vous utilisez PyCharm, vous pouvez facilement parcourir et ajouter de nouveaux mod\u00e8les provenant de Hugging Face. Dans un nouveau fichier Python, dans le menu <em>Code<\/em> en haut, s\u00e9lectionnez <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=\"Utilisation des mod\u00e8les de Hugging Face\" width=\"946\" height=\"1070\" \/><\/figure>\n<p>Dans le menu qui s&#8217;ouvre, vous pouvez parcourir les mod\u00e8les par cat\u00e9gorie ou saisir votre recherche dans la barre pr\u00e9vue \u00e0 cet effet en haut. Lorsque vous s\u00e9lectionnez un mod\u00e8le, sa description s&#8217;affiche \u00e0 sa droite.<\/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=\"Explorer des mod\u00e8les de Hugging Face\" width=\"1600\" height=\"923\" \/><\/figure>\n<p>Cliquez sur <em>Use Model<\/em> pour ajouter un extrait de code \u00e0 votre fichier. Et voil\u00e0, il ne vous reste plus qu&#8217;\u00e0 utiliser votre mod\u00e8le 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=\"Utiliser des mod\u00e8les Hugging Face dans PyCharm\" width=\"1600\" height=\"312\" \/><\/figure>\n<h2 class=\"wp-block-heading\">Mod\u00e8les GPT (Generative Pre-Trained Transformer &#8211; Transformer g\u00e9n\u00e9ratif pr\u00e9-entra\u00een\u00e9)<\/h2>\n<p>Les mod\u00e8les GPT sont tr\u00e8s populaires sur <a href=\"https:\/\/huggingface.co\/models\" target=\"_blank\" rel=\"noopener\">Hugging Face Hub<\/a>, mais de quoi s&#8217;agit-il ? Les mod\u00e8les GPT d\u00e9signent des mod\u00e8les entra\u00een\u00e9s capables de comprendre le langage naturel et de g\u00e9n\u00e9rer du texte de haute qualit\u00e9. Ils sont principalement utilis\u00e9s dans des t\u00e2ches li\u00e9es \u00e0 l&#8217;implication textuelle, \u00e0 la r\u00e9ponse \u00e0 des questions, \u00e0 la similarit\u00e9 s\u00e9mantique et \u00e0 la classification de documents. L&#8217;exemple le plus c\u00e9l\u00e8bre est <a href=\"https:\/\/openai.com\/index\/chatgpt\/\" target=\"_blank\" rel=\"noopener\">ChatGPT, cr\u00e9\u00e9 par OpenAI<\/a>.<\/p>\n<p>De nombreux mod\u00e8les OpenAI GPT sont disponibles sur <a href=\"https:\/\/huggingface.co\/models\" target=\"_blank\" rel=\"noopener\">Hugging Face Hub<\/a>. Nous allons voir comment les utiliser avec Transformers, les ajuster avec nos propres donn\u00e9es et les d\u00e9ployer dans une application.<\/p>\n<h2 class=\"wp-block-heading\">Avantages de l&#8217;utilisation de Transformers<\/h2>\n<p>Transformers, associ\u00e9 \u00e0 d&#8217;autres outils de Hugging Face, offre des outils avanc\u00e9s permettant d&#8217;ajuster n&#8217;importe quel mod\u00e8le sophistiqu\u00e9 de deep learning. Si vous ne souhaitez pas vous pencher sur les d\u00e9tails de l&#8217;architecture d&#8217;un mod\u00e8le donn\u00e9 et de sa m\u00e9thode de tokenisation, utilisez ces outils pour cr\u00e9er des mod\u00e8les \u00ab\u00a0plug and play\u00a0\u00bb \u00e0 partir des donn\u00e9es d\u2019entra\u00eenement compatibles. Ils offrent par ailleurs de nombreuses possibilit\u00e9s de personnalisation de la tokenisation et de l&#8217;entra\u00eenement.<\/p>\n<h2 class=\"wp-block-heading\">Transformers en action<\/h2>\n<p>Pour voir de plus pr\u00e8s comment fonctionne Transformers, regardons comment l&#8217;utiliser pour interagir avec un mod\u00e8le GPT.<\/p>\n<h3 class=\"wp-block-heading\">Inf\u00e9rence au moyen d&#8217;un mod\u00e8le pr\u00e9-entra\u00een\u00e9 avec un pipeline<\/h3>\n<p>Apr\u00e8s avoir s\u00e9lectionn\u00e9 et ajout\u00e9 le mod\u00e8le GPT-2 d&#8217;OpenAI au code, nous obtenons ce qui suit :<\/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>Avant de l&#8217;utiliser, nous devons effectuer quelques pr\u00e9paratifs. Tout d&#8217;abord, nous devons installer un framework de machine learning. Dans cet exemple, nous avons choisi <a href=\"https:\/\/pytorch.org\/get-started\/locally\/\" target=\"_blank\" rel=\"noopener\">PyTorch<\/a>. Vous pouvez l&#8217;installer facilement via la fen\u00eatre <em>Python Packages<\/em> dans 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=\"Installation de PyTorch dans PyCharm\" width=\"920\" height=\"654\" \/><\/figure>\n<p>Ensuite, nous devons installer Transformers avec l&#8217;option `torch`. Pour ce faire, utilisez le terminal. Ouvrez-le en utilisant le bouton de gauche ou utilisez les touches de raccourci <em>\u2325 F12 <\/em>(macOS) ou <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=\"Installation de Transformers dans le terminal de PyCharm\" width=\"838\" height=\"502\" \/><\/figure>\n<p>Dans le terminal, dans la mesure o\u00f9 nous utilisons uv, nous devons utiliser les commandes suivantes pour ajouter l&#8217;ensemble en tant que d\u00e9pendance et l&#8217;installer :<\/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 vous utilisez 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>Nous allons \u00e9galement installer quelques autres biblioth\u00e8ques dont nous aurons besoin par la suite, avec notamment python-dotenv, datasets, notebook et ipywidgets. Vous pouvez utiliser l&#8217;une des m\u00e9thodes ci-dessus pour les installer.<br \/>Ensuite, il peut \u00eatre pr\u00e9f\u00e9rable d&#8217;ajouter un GPU pour acc\u00e9l\u00e9rer le mod\u00e8le. Selon la configuration de votre ordinateur, vous pouvez l&#8217;ajouter en d\u00e9finissant le param\u00e8tre device dans le pipeline. Puisque j&#8217;utilise un Mac M2, je peux d\u00e9finir <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">device=\"mps\"<\/code> de la fa\u00e7on suivante :<\/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 vous avez des GPU CUDA, vous pouvez \u00e9galement utiliser <code class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">device=\"cuda\"<\/code>.<\/p>\n<p>Maintenant que le pipeline est configur\u00e9, nous allons faire un essai avec un prompt simple :<\/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>Cliquez sur le bouton <em>Run<\/em>, en haut, pour ex\u00e9cuter le script (<img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/AD_4nXf6ZDm7vSGyFlO0DzXegK6WP9JxsStUiJA-bkRZ0mwPsUsmn8M70emV5Sr8f17-fEK6z9V1EQKWEm3RPHdT8n8uqG18faVmQn5y09psVInQLU0CZQKXAEg2q7m7AOsh4hPU7G8gcQ.png\" width=\"30\" height=\"23\" \/>) :<\/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=\"Ex\u00e9cution du script dans PyCharm\" width=\"1050\" height=\"282\" \/><\/figure>\n<p>Le r\u00e9sultat prend la forme suivante :<\/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>Il n&#8217;y a pratiquement aucun raisonnement, juste une suite de mots.\u00a0<\/p>\n<p>Vous verrez peut-\u00eatre \u00e9galement cet avertissement :<\/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>Il s&#8217;agit du param\u00e8tre par d\u00e9faut. Vous pouvez \u00e9galement l&#8217;ajouter manuellement comme indiqu\u00e9 ci-dessous, pour faire dispara\u00eetre l&#8217;avertissement, mais nous n&#8217;avons pas vraiment \u00e0 nous en pr\u00e9occuper \u00e0 ce stade.<\/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>Maintenant que nous avons vu comment GPT-2 fonctionne tel quel, nous allons essayer d&#8217;am\u00e9liorer son raisonnement math\u00e9matique.<\/p>\n<h3 class=\"wp-block-heading\">Chargement et pr\u00e9paration d&#8217;un ensemble de donn\u00e9es depuis Hugging Face Hub<\/h3>\n<p>Avant de travailler sur le mod\u00e8le GPT, nous avons d&#8217;abord besoin de donn\u00e9es d&#8217;entra\u00eenement. Voyons comment obtenir un ensemble de donn\u00e9es depuis Hugging Face Hub.<\/p>\n<p>Si ce n&#8217;est pas d\u00e9j\u00e0 fait, cr\u00e9ez un compte Hugging Face, ainsi qu&#8217;un <a href=\"https:\/\/huggingface.co\/docs\/hub\/security-tokens#user-access-tokens\" target=\"_blank\" rel=\"noopener\">jeton d&#8217;acc\u00e8s<\/a>. Nous n&#8217;avons besoin que d&#8217;un jeton `read` pour l&#8217;instant. Stockez votre jeton dans un fichier `.env` de la fa\u00e7on suivante :<\/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>Nous allons utiliser <a href=\"https:\/\/huggingface.co\/datasets\/Cheukting\/math-meta-reasoning-cleaned\" target=\"_blank\" rel=\"noopener\">Math Reasoning Dataset<\/a>, qui comporte du texte d\u00e9crivant des raisonnements math\u00e9matiques. Nous allons ajuster notre mod\u00e8le GPT avec cet ensemble de donn\u00e9e afin qu&#8217;il puisse r\u00e9soudre plus efficacement les probl\u00e8mes math\u00e9matiques.<\/p>\n<p>Nous allons cr\u00e9er un notebook Jupyter, que nous utiliserons pour l&#8217;ajustement, car il permet d&#8217;ex\u00e9cuter diff\u00e9rents extraits de code un par un et de suivre la progression.<\/p>\n<p>Dans la premi\u00e8re cellule, nous allons utiliser ce script pour charger l&#8217;ensemble de donn\u00e9es depuis 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>Ex\u00e9cutez cette cellule (cela peut prendre du temps selon le d\u00e9bit de votre connexion Internet) pour t\u00e9l\u00e9charger l&#8217;ensemble de donn\u00e9es. Une fois cette op\u00e9ration termin\u00e9e, nous pouvons examiner les r\u00e9sultats :<\/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 vous \u00eates curieux et souhaitez jeter un \u0153il sur les donn\u00e9es, vous pouvez le faire dans PyCharm. Ouvrez la fen\u00eatre <em>Jupyter Variables<\/em> en utilisant le bouton de droite :<\/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=\"Ouverture des variables Jupyter dans PyCharm\" width=\"1052\" height=\"740\" \/><\/figure>\n<p>D\u00e9veloppez la section <em>dataset<\/em> pour voir l&#8217;option <em>View as DataFrame<\/em> pr\u00e8s de <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=\"Variables Jupyter dans PyCharm\" width=\"980\" height=\"882\" \/><\/figure>\n<p>Cliquez dessus pour examiner les donn\u00e9es dans la fen\u00eatre d&#8217;outils <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=\"Outil Data View dans PyCharm\" width=\"980\" height=\"1102\" \/><\/figure>\n<p>Ensuite, nous allons tokeniser le texte de l&#8217;ensemble de donn\u00e9es :<\/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>Ici, nous utilisons le tokenizer GPT-2 et d\u00e9finissons <code>pad_token<\/code> sur <code>eos_token<\/code> : il s&#8217;agit du jeton de fin de ligne. Ensuite, nous allons tokeniser le texte avec une fonction. La premi\u00e8re ex\u00e9cution risque d&#8217;\u00eatre laborieuse, mais ensuite, les donn\u00e9es seront en m\u00e9moire cache et permettront de r\u00e9ex\u00e9cuter la cellule plus rapidement.<\/p>\n<p>Le jeu de donn\u00e9es comporte plus de 1 million de lignes pour l&#8217;entra\u00eenement. Si vous disposez de suffisamment de puissance de calcul pour les traiter toutes, vous pouvez toutes les utiliser. Dans la mesure o\u00f9 la pr\u00e9sente d\u00e9monstration consiste en un entra\u00eenement local sur un ordinateur portable, je n&#8217;en utiliserai qu&#8217;une petite partie !<\/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>Ici, je ne prends que 1 % des donn\u00e9es, puis j&#8217;ex\u00e9cute <code>train_test_split<\/code> pour diviser l&#8217;ensemble de donn\u00e9es en deux :<\/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>Nous sommes d\u00e9sormais pr\u00eats \u00e0 ajuster le mod\u00e8le GPT-2.<\/p>\n<h3 class=\"wp-block-heading\">Ajuster un mod\u00e8le GPT<\/h3>\n<p>Nous allons utiliser la cellule vide suivante pour d\u00e9finir nos arguments d&#8217;entra\u00eenement :<\/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 plupart d&#8217;entre eux sont assez standards pour l&#8217;ajustement d&#8217;un mod\u00e8le. Toutefois, selon la configuration de votre ordinateur, il peut \u00eatre n\u00e9cessaire d&#8217;ajuster plusieurs choses :<\/p>\n<ul>\n<li>Taille de lot : d\u00e9terminer la taille de lot optimale est important, car plus elle est grande, plus l&#8217;entra\u00eenement sera rapide. Toutefois, la m\u00e9moire disponible de votre CPU ou GPU est limit\u00e9e, ce qui cr\u00e9e donc un seuil maximal.<\/li>\n<li>\u00c9poques : l&#8217;augmentation du nombre d&#8217;\u00e9poques prolonge l&#8217;entra\u00eenement. Vous pouvez d\u00e9finir le nombre d&#8217;\u00e9poques dont vous avez besoin.<\/li>\n<li>\u00c9tapes d&#8217;enregistrement : les \u00e9tapes d&#8217;enregistrement conditionnent la fr\u00e9quence d&#8217;enregistrement d&#8217;un point de contr\u00f4le sur un disque. Si l&#8217;entra\u00eenement est lent et qu&#8217;il y a un risque d&#8217;arr\u00eat impromptu, il peut \u00eatre n\u00e9cessaire de faire des enregistrements plus fr\u00e9quents (en diminuant cette valeur).<\/li>\n<\/ul>\n<p>\u00a0Une fois l&#8217;ensemble de nos param\u00e8tres configur\u00e9s, nous allons mettre en place le module d&#8217;entra\u00eenement (trainer) dans la cellule suivante :<\/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>Nous avons d\u00e9fini `resume_from_checkpoint=False`, mais vous pouvez remplacer cela par `True` pour reprendre depuis le dernier point de contr\u00f4le si l&#8217;entra\u00eenement a \u00e9t\u00e9 interrompu.<\/p>\n<p>Une fois l&#8217;entra\u00eenement termin\u00e9, nous allons \u00e9valuer et enregistrer le mod\u00e8le :<\/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>Nous pouvons d\u00e9sormais utiliser le mod\u00e8le entra\u00een\u00e9 dans le pipeline. Revenons pour cela \u00e0 `model.py`, o\u00f9 nous avons utilis\u00e9 un pipeline avec un mod\u00e8le pr\u00e9-entra\u00een\u00e9 :<\/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>Nous allons maintenant remplacer `model=\u201dopenai-community\/gpt2\u2033` par model=\u201d.\/trained_model\u201d` et voir le r\u00e9sultat\u00a0:<\/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>Malheureusement, cela ne r\u00e9sout toujours pas le probl\u00e8me. Cependant, il a produit quelques formules math\u00e9matiques et un raisonnement qu&#8217;il n&#8217;utilisait pas avant. Si vous le souhaitez, vous pouvez pousser l&#8217;optimisation du mod\u00e8le avec les donn\u00e9es que nous n&#8217;avons pas utilis\u00e9es.<\/p>\n<p>Dans la section suivante, nous allons voir comment d\u00e9ployer un mod\u00e8le optimis\u00e9 sur les points de terminaison d&#8217;API en utilisant \u00e0 la fois les outils de Hugging Face et ceux de FastAPI.<\/p>\n<h2 class=\"wp-block-heading\">D\u00e9ploiement d&#8217;un mod\u00e8le optimis\u00e9<\/h2>\n<p>La solution la plus simple pour d\u00e9ployer un mod\u00e8le sur un backend de serveur consiste \u00e0 utiliser FastAPI. J&#8217;ai \u00e9crit un <a href=\"https:\/\/blog.jetbrains.com\/pycharm\/2024\/09\/how-to-use-fastapi-for-machine-learning\/\">article de blog<\/a> sur le d\u00e9ploiement d&#8217;un mod\u00e8le de machine learning avec FastAPI. Nous n&#8217;allons pas entrer aussi loin dans les d\u00e9tails ici, mais nous allons voir comment d\u00e9ployer notre mod\u00e8le optimis\u00e9.<\/p>\n<p>Avec l&#8217;aide de <a href=\"https:\/\/www.jetbrains.com\/fr-fr\/junie\/\" target=\"_blank\" rel=\"noopener\">Junie<\/a>, nous avons cr\u00e9\u00e9 des scripts que vous pouvez voir <a href=\"https:\/\/github.com\/Cheukting\/fine-tune-gpt2\/tree\/main\/app\" target=\"_blank\" rel=\"noopener\">ici<\/a>. Ces scripts nous permettent de d\u00e9ployer un backend de serveur avec des points de terminaison FastAPI.\u00a0<\/p>\n<p>Nous devons ajouter quelques nouvelles d\u00e9pendances :<\/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>Examinons quelques points int\u00e9ressants des scripts, dans `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>Une fois l&#8217;application initialis\u00e9e, le script tente de charger le mod\u00e8le dans un pipeline. Si aucun GPU Metal n&#8217;est disponible, le CPU est utilis\u00e9. Si vous avez un GPU CUDA au lieu d&#8217;un GPU Metal, vous pouvez remplacer `mps` par `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>Deux nouvelles classes sont cr\u00e9\u00e9es et elles h\u00e9ritent de `BaseModel` de Pydantic.<\/p>\n<p>Nous pouvons \u00e9galement inspecter nos points de terminaison avec la fen\u00eatre d&#8217;outils <em>Endpoints<\/em>. Cliquez sur le globe pr\u00e8s de `app = FastAPI` \u00e0 la ligne 11 et s\u00e9lectionnez <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=\"Affichage de tous les points de terminaison dans PyCharm\" width=\"1600\" height=\"833\" \/><\/figure>\n<p>Nous avons trois points de terminaison. Dans la mesure o\u00f9 le point de terminaison root est un simple message d&#8217;accueil, nous allons examiner les deux autres.<\/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>Le point de terminaison `\/generate` collecte le prompt de la requ\u00eate et g\u00e9n\u00e8re le texte de la r\u00e9ponse \u00e0 partir du mod\u00e8le.<\/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>Le point de terminaison `\/health` v\u00e9rifie si le mod\u00e8le est charg\u00e9 correctement. Cela peut \u00eatre utile si l&#8217;application c\u00f4t\u00e9 client doit effectuer une v\u00e9rification avant de rendre l&#8217;autre point de terminaison disponible dans son interface utilisateur.<\/p>\n<p>Dans `run.py`, nous utilisons <a href=\"https:\/\/www.uvicorn.org\/\" target=\"_blank\" rel=\"noopener\">uvicorn<\/a> pour ex\u00e9cuter le serveur :<\/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>Lorsque nous ex\u00e9cutons ce script, le serveur d\u00e9marre sur <a href=\"http:\/\/0.0.0.0:8000\/\" target=\"_blank\" rel=\"noopener\">http:\/\/0.0.0.0:8000\/<\/a>.<\/p>\n<p>Apr\u00e8s le lancement du serveur, nous pouvons aller \u00e0 <a href=\"http:\/\/0.0.0.0:8000\/docs\" target=\"_blank\" rel=\"noopener\">http:\/\/0.0.0.0:8000\/docs<\/a> pour tester les points de terminaison.\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>Nous pouvons essayer cela avec le point de terminaison `\/generate`\u00a0:<\/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>Voici la r\u00e9ponse obtenue :<\/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>N&#8217;h\u00e9sitez pas \u00e0 essayer d&#8217;autres requ\u00eates.<\/p>\n<h2 class=\"wp-block-heading\">Conclusion et prochaines \u00e9tapes<\/h2>\n<p>Maintenant que vous avez optimis\u00e9 avec succ\u00e8s un LLM comme GPT-2 avec un ensemble de donn\u00e9es de raisonnement math\u00e9matique et que vous l&#8217;avez d\u00e9ploy\u00e9 avec FastAPI, vous pouvez ajuster de nombreux autres LLM open source disponibles sur Hugging Face Hub. Vous pouvez exp\u00e9rimenter l&#8217;ajustement d&#8217;autres mod\u00e8les de LLM avec les donn\u00e9es open source disponibles ou avec vos propres ensembles de donn\u00e9es. Si vous le souhaitez (et si la licence du mod\u00e8le d&#8217;origine le permet), vous pouvez \u00e9galement charger votre propre mod\u00e8le optimis\u00e9 sur Hugging Face Hub. Consultez sa <a href=\"https:\/\/huggingface.co\/docs\/transformers\/v4.53.3\/en\/main_classes\/trainer#transformers.Trainer.push_to_hub\" target=\"_blank\" rel=\"noopener\">documentation<\/a> pour d\u00e9terminer comment proc\u00e9der.<\/p>\n<p>Une derni\u00e8re remarque concernant l&#8217;utilisation ou l&#8217;ajustement de mod\u00e8les avec des ressources sur Hugging Face Hub : veillez \u00e0 lire les licences de tout mod\u00e8le ou ensemble de donn\u00e9es que vous utilisez afin de comprendre les conditions d&#8217;utilisation de ces ressources. Peuvent-elles \u00eatre utilis\u00e9es \u00e0 des fins commerciales ? Devez-vous citer les auteurs des ressources utilis\u00e9es ?<\/p>\n<p>Dans les prochains articles de blog, nous allons explorer d&#8217;autres exemples de code portant sur Python, l&#8217;IA, le machine learning et la visualisation des donn\u00e9es.<\/p>\n<p>Selon moi, <a href=\"https:\/\/www.jetbrains.com\/fr-fr\/pycharm\/\" target=\"_blank\" rel=\"noopener\">PyCharm<\/a> offre une prise en charge optimale de Python, que ce soit en termes de vitesse ou de pr\u00e9cision. Vous profitez ainsi d&#8217;une saisie semi-automatique avanc\u00e9e, de v\u00e9rifications de conformit\u00e9 PEP 8, de refactorisations intelligentes et de nombreuses inspections pour r\u00e9pondre \u00e0 tous vos besoins en mati\u00e8re de programmation. Comme illustr\u00e9 dans cet article de blog, PyCharm assure l&#8217;int\u00e9gration avec Hugging Face Hub, ce qui vous permet de naviguer et d&#8217;utiliser des mod\u00e8les sans quitter l&#8217;IDE. Cela en fait un excellent outil pour une large gamme de projets d&#8217;IA et d&#8217;optimisation de LLM.<\/p>\n<div class=\"buttons\">\n<div class=\"buttons__row\"><a class=\"btn\" href=\"https:\/\/www.jetbrains.com\/fr-fr\/pycharm\/\" target=\"\" rel=\"noopener\">T\u00e9l\u00e9chargez PyCharm d\u00e8s maintenant<\/a><\/div>\n<\/div>\n<div>\u00a0<\/div>\n<div><em>Auteur de l&#8217;article original en anglais<\/em> :\u00a0<\/div>\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":813,"featured_media":649025,"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\/fr\/wp-json\/wp\/v2\/pycharm\/649021"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/pycharm"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/pycharm"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/813"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=649021"}],"version-history":[{"count":6,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/pycharm\/649021\/revisions"}],"predecessor-version":[{"id":649051,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/pycharm\/649021\/revisions\/649051"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media\/649025"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=649021"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=649021"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=649021"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=649021"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}