{
  "source_file": "0930",
  "source_platform": "Substack",
  "author": "Sebastian Raschka / Ahead of AI",
  "title_listed": "Finetuning Large Language Models",
  "keywords": "微调,LLM,参数高效",
  "domain": "大模型算法",
  "content_type": "深度技术解析",
  "is_paid_flag": "否",
  "url": "https://magazine.sebastianraschka.com/p/finetuning-large-language-models",
  "publish_date": "2023-09",
  "corpus_stage": "预训练/SFT",
  "notes": "LLM微调综述",
  "id": "54531b58b406",
  "collected_at": "2026-10-01T20:32:47",
  "title": "Finetuning Large Language Models",
  "body_markdown": "In the rapidly evolving field of artificial intelligence, utilizing large language models (LLMs) efficiently and effectively has become increasingly important. But we can use large language models in many different ways, which can be overwhelming if you are starting out.\nIn essence, we can use pretrained large language models for new tasks in two main ways: in-context learning and finetuning.\nIn this article, we will briefly go over what in-context learning means, and then we will go over the various ways we can finetune LLMs.\nIn-Context Learning and Indexing\nSince GPT-2 (\nRadford et al.\n) and GPT-3 (\nBrown et al.\n), we have seen that generative large language models (LLMs) pretrained on a general text corpus are capable of\nin-context learning\n, which doesn’t require us to further train or finetune pretrained LLMs if we want to perform specific or new tasks that the LLM wasn’t explicitly trained on. Instead, we can directly provide a few examples of a target task via the input prompt, as illustrated in the example below.\nAn example of in-context learning.\nIn-context learning is very useful if we don’t have direct access to the model, for instance, if we are using the model through an API.\nRelated to in-context learning is the concept of\nhard prompt tuning\nwhere we modify the inputs in hope to improve the outputs as illustrated below.\nAn illustration of (hard) prompt tuning\nBy the way, we call it\nhard\nprompt tuning because we are modifying the input words or tokens directly. Later on, we will discuss a differentiable version referred to as\nsoft\nprompt tuning (or often just called\nprompt tuning\n).\nThe prompt tuning approach mentioned above offers a more resource-efficient alternative to parameter finetuning. However, its performance typically falls short of finetuning, as it doesn't update the model's parameters for a specific task, which may limit its adaptability to task-specific nuances. Moreover, prompt tuning can be labor-intensive, as it often demands human involvement in comparing the quality of different prompts.\nBefore we discuss finetuning in more detail, another method to utilize a purely in-context learning-based approach is\nindexing\n. Within the realm of LLMs, indexing can be seen as an in-context learning workaround that enables the conversion of LLMs into information retrieval systems for extracting data from external resources and websites. In this process, an indexing module breaks down a document or website into smaller segments, converting them into vectors that can be stored in a vector database. Then, when a user submits a query, the indexing module calculates the vector similarity between the embedded query and each vector in the database. Ultimately, the indexing module fetches the top\nk\nmost similar embeddings to generate the response.\nAn illustration of indexing.\nThe 3 Conventional Feature-Based and Finetuning Approaches\nIn-context learning is a valuable and user-friendly method for situations where direct access to the large language model (LLM) is limited, such as when interacting with the LLM through an API or user interface.\nHowever, if we have access to the LLM, adapting and finetuning it on a target task using data from a target domain usually leads to superior results. So, how can we adapt a model to a target task? There are three conventional approaches outlined in the figure below.\nThe 3 conventional feature-based and finetuning approaches.\nTo provide some practical context for the discussions below, we are finetuning an encoder-style LLM such as BERT (\nDevlin et al. 2018\n) for a classification task. (To keep things simple, this classification task predicts whether a movie review has a positive or negative sentiment.) Note that instead of finetuning an encoder-style LLM, the same approach would work for GPT-like decoder-style LLMs, and I will provide an example of this in a future article. Furthermore, we can also finetuning decoder-style LLMs to generate multiple-sentence answers to specific instructions instead of just classifying texts. Also, for this, I will provide hands-on examples in future articles.\n1) Feature-Based Approach\nIn the feature-based approach, we load a pretrained LLM and apply it to our target dataset. Here, we are particularly interested in generating the output embeddings for the training set, which we can use as input features to train a classification model. While this approach is particularly common for embedding-focused like BERT, we can also extract embeddings from generative GPT-style model.\nThe classification model can then be a logistic regression model, a random forest, or XGBoost – whatever our hearts desire. (However, based on my experience, linear classifiers like logistic regression perform best here.)\nConceptually, we can illustrate the feature-based approach with the following code:\nmodel = AutoModel.from_pretrained(\"distilbert-base-uncased\")\n\n# ...\n# tokenize dataset\n# ...\n\n# generate embeddings\n@torch.inference_mode()\ndef get_output_embeddings(batch): \n    output = model(\n        batch[\"input_ids\"],\n        attention_mask=batch[\"attention_mask\"]\n    ).last_hidden_state[:, 0]\nreturn {\"features\": output}\n  \ndataset_features = dataset_tokenized.map(\n  get_output_embeddings, batched=True, batch_size=10)\n\nX_train = np.array(imdb_features[\"train\"][\"features\"])\ny_train = np.array(imdb_features[\"train\"][\"label\"])\n\nX_val = np.array(imdb_features[\"validation\"][\"features\"])\ny_val = np.array(imdb_features[\"validation\"][\"label\"])\n\nX_test = np.array(imdb_features[\"test\"][\"features\"])\ny_test = np.array(imdb_features[\"test\"][\"label\"])\n\n# train classifier\nfrom sklearn.linear_model import LogisticRegression\n\nclf = LogisticRegression()\nclf.fit(X_train, y_train)\n\nprint(\"Training accuracy\", clf.score(X_train, y_train))\nprint(\"Validation accuracy\", clf.score(X_val, y_val))\nprint(\"test accuracy\", clf.score(X_test, y_test))\n(Interested readers can find the full code example\nhere\n.)\n2) Finetuning I – Updating The Output Layers\nA popular approach related to the feature-based approach described above is finetuning the output layers (we will refer to this approach as\nfinetuning I\n). Similar to the feature-based approach, we keep the parameters of the pretrained LLM frozen. We only train the newly added output layers, analogous to training a logistic regression classifier or small multilayer perceptron on the embedded features.\nIn code, this would look as follows:\nmodel = AutoModelForSequenceClassification.from_pretrained(\n    \"distilbert-base-uncased\",\n     num_labels=2\n) \n\n# freeze all layers\nfor param in model.parameters():\n    param.requires_grad = False\n    \n# then unfreeze the two last layers (output layers)\nfor param in model.pre_classifier.parameters():\n    param.requires_grad = True\n\nfor param in model.classifier.parameters():\n    param.requires_grad = True\n    \n# finetune model\nlightning_model = CustomLightningModule(model)\n\ntrainer = L.Trainer(\n    max_epochs=3,\n    ...\n)\n\ntrainer.fit(\n  model=lightning_model,\n  train_dataloaders=train_loader,\n  val_dataloaders=val_loader)\n\n# evaluate model\ntrainer.test(lightning_model, dataloaders=test_loader)\n(Interested readers can find the complete code example\nhere\n.)\nIn theory, this approach should perform similarly well, in terms of modeling performance and speed, as the feature-based approach since we use the same frozen backbone model. However, since the feature-based approach makes it slightly easier to pre-compute and store the embedded features for the training dataset, the feature-based approach may be more convenient for specific practical scenarios.\n3) Finetuning II – Updating All Layers\nWhile the original BERT paper (\nDevlin et al.\n) reported that finetuning only the output layer can result in modeling performance comparable to finetuning all layers, which is substantially more expensive since more parameters are involved. For instance, a BERT base model has approximately 110 million parameters. However, the final layer of a BERT base model for binary classification consists of merely 1,500 parameters. Furthermore, the last two layers of a BERT base model account for 60,000 parameters – that’s only around 0.6% of the total model size.\nOur mileage will vary based on how similar our target task and target domain is to the dataset the model was pretrained on. But in practice, finetuning all layers almost always results in superior modeling performance.\nSo, when optimizing the modeling performance, the gold standard for using pretrained LLMs is to update all layers (here referred to as finetuning II). Conceptually finetuning II is very similar to finetuning I. The only difference is that we do not freeze the parameters of the pretrained LLM but finetune them as well:\nmodel = AutoModelForSequenceClassification.from_pretrained(\n    \"distilbert-base-uncased\",\n     num_labels=2\n) \n\n# freeze layers (which we don't do here)\n# for param in model.parameters():\n#    param.requires_grad = False\n    \n\n# finetune model\nlightning_model = LightningModel(model)\n\ntrainer = L.Trainer(\n    max_epochs=3,\n    ...\n)\n\ntrainer.fit(\n  model=lightning_model,\n  train_dataloaders=train_loader,\n  val_dataloaders=val_loader)\n\n# evaluate model\ntrainer.test(lightning_model, dataloaders=test_loader)\n(Interested readers can find the complete code example\nhere\n.)\nIf you are curious about some real-world results, the code snippets above were used to train a movie review classifier using a pretrained DistilBERT base model (you can access the code notebooks\nhere\n):\n1) Feature-based approach with logistic regression: 83% test accuracy\n2) Finetuning I, updating the last 2 layers: 87% accuracy\n3) Finetuning II, updating all layers: 92% accuracy.\nThese results are consistent with the general rule of thumb that finetuning more layers often results in better performance, but it comes with increased cost.\nRule-of-thumb computational and modeling performance trade-offs for various approaches.\nThe scenarios above highlighted the three most distinct or extreme cases of finetuning: training only the last layer(s) versus training all layers. Of course, our mileage may vary based on the model and dataset, but exploring the various options in between may also be worthwhile. For instance, we can sometimes get the same modeling performance by training only half of the model (but more on parameter-efficient finetuning in the next section). For those who are curious, the figure below shows the predictive performances and training times for a DistilBERT model finetuned on the 20k training examples from the\nIMDB movie review dataset\n.\nPerformance of pretrained DistilBERT models finetuned on the IMDB Movie review dataset. The code can be found\nhere on GitHub\n.\nAs we can see, training the last layer is the fastest but also results in the poorest modeling performance. As expected, training more layers improves the modeling performance but it also increases the computational cost. Most interestingly, we can see the predictive performance saturate when training the two fully connected output layers and the last two transformer blocks (the third block from the left). So, in this particular case (that is, for this particular model and dataset combination), it seems computationally wasteful to train more than these layers.\nParameter-Efficient Finetuning\nParameter-efficient finetuning\nallows us to reuse pretrained models while minimizing the computational and resource footprints. In sum, parameter-efficient finetuning is useful for at least 5 reasons:\nReduced computational costs (requires fewer GPUs and GPU time);\nFaster training times (finishes training faster);\nLower hardware requirements (works with smaller GPUs & less smemory);\nBetter modeling performance (reduces overfitting);\nLess storage (majority of weights can be shared across different tasks).\nIn the previous sections, we learned that finetuning more layers usually leads to better results. Now, the experiments above are based on a DistilBERT model, which is relatively small. What if we want to finetune larger models that only barely fit into GPU memory, for example, the latest generative LLMs? We can use the feature-based or finetuning I approach above, of course. But suppose we want to get a similar modeling quality as finetuning II?\nOver the years, researchers developed several techniques (\nLialin et al.\n) to finetune LLM with high modeling performance while\nonly requiring the training of only a small number of parameters\n. These methods are usually referred to as parameter-efficient finetuning techniques (PEFT).\nSome of the most widely used PEFT techniques are summarized in the figure below.\nA selection of the most popular parameter-efficient finetuning techniques.\nSo, how do these techniques work? In a nutshell, they all involve introducing a small number of additional parameters that we finetuned (as opposed to finetuning all layers as we did in the Finetuning II approach above). In a sense, Finetuning I (only finetuning the last layer) could also be considered a parameter-efficient finetuning technique. However, techniques such as prefix tuning, adapters, and low-rank adaptation, all of which “modify” multiple layers, achieve much better predictive performance (at a low cost).\nSince this is already a very long article, and since these are super interesting techniques, I will cover these techniques separately in the future.\nReinforcement Learning with Human Feedback\nIn Reinforcement Learning with Human Feedback (RLHF), a pretrained model is finetuned using a combination of supervised learning and reinforcement learning -- the approach was popularized by the original ChatGPT model, which was in turn based on InstructGPT (\nOuyang et al.\n).\nIn RLHF, human feedback is collected by having humans rank or rate different model outputs, providing a reward signal. The collected reward labels can then be used to train a reward model that is then in turn used to guide the LLMs adaptation to human preferences.\nThe reward model itself is learned via supervised learning (typically using a pretrained LLM as base model). Next, the reward model is used to update the pretrained LLM that is to be adapted to human preferences -- the training uses a flavor of reinforcement learning called proximal policy optimization (\nSchulman et al.\n).\nScreenshot from the InstructGPT paper outlining the RLHF process.\nWhy use a reward model instead of training the pretained model on the human feedback directly? That's because involving humans in the learning process would create a bottleneck since we cannot obtain feedback in real-time.\nAs mentioned above, the article is already very long, so I am deferring a more detailed explanation to a future article.\nConclusion\nFine-tuning all layers of a pretrained LLM remains the gold standard for adapting to new target tasks, but there are several efficient alternatives for using pretrained transformers. Methods such as feature-based approaches, in-context learning, and parameter-efficient finetuning techniques enable effective application of LLMs to new tasks while minimizing computational costs and resources.\nMoreover, reinforcement learning with human feedback (RLHF) serves as an alternative to supervised finetuning, potentially enhancing model performance.\nThis magazine is a personal passion project. For those who wish to support me beyond a\npaid subscription\n, please consider purchasing a copy of\none of my books\n. If you find them insightful and beneficial, please feel free to recommend them to your friends and colleagues.\nMachine Learning with PyTorch and Scikit-Learn\n,\nMachine Learning Q and AI\n, and\nBuild a Large Language Model (from Scratch)\nYour support means a great deal! Thank you!",
  "metadata": {
    "title": "Finetuning Large Language Models",
    "description": "Dive into the realm of artificial intelligence with this comprehensive guide on effectively using Large Language Models (LLMs). From in-context learning and indexing to the nitty-gritty of finetuning, we break down the complexities for beginners.",
    "keywords": null,
    "author": "Sebastian Raschka, PhD",
    "og:type": "article",
    "og:title": "Finetuning Large Language Models",
    "og:description": "An introduction to the core ideas and approaches",
    "og:image": "https://substackcdn.com/image/fetch/$s_!lJ3t!,w_1200,h_675,c_fill,f_jpg,q_auto:good,fl_progressive:steep,g_auto/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa534808e-9284-47eb-9b4d-3e3aedc0b5da_1180x842.png",
    "og:url": "https://magazine.sebastianraschka.com/p/finetuning-large-language-models",
    "twitter:title": "Finetuning Large Language Models",
    "twitter:description": "An introduction to the core ideas and approaches",
    "twitter:image": "https://substackcdn.com/image/fetch/$s_!FEW4!,f_auto,q_auto:best,fl_progressive:steep/https%3A%2F%2Fsebastianraschka.substack.com%2Fapi%2Fv1%2Fpost_preview%2F115943216%2Ftwitter.jpg%3Fversion%3D4",
    "twitter:card": "summary_large_image",
    "article:modified_time": "2025-03-07T20:57:05.509Z"
  },
  "paywall": {
    "listed_paid": false,
    "detected": false,
    "marker": "",
    "public_only": false,
    "policy": "付费/会员内容只保留页面公开可见部分，不绕过付费墙"
  },
  "crawl": {
    "success": true,
    "status_code": 200,
    "error": ""
  },
  "code_blocks": [
    {
      "file": "attachments/54531b58b406/code/body-000.txt",
      "chars": 1039,
      "language": "text"
    },
    {
      "file": "attachments/54531b58b406/code/body-001.txt",
      "chars": 704,
      "language": "text"
    },
    {
      "file": "attachments/54531b58b406/code/body-002.txt",
      "chars": 510,
      "language": "text"
    }
  ],
  "images": [
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!-lkw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffea460ea-84d5-4973-9bc7-dc0e53a13ae0_1340x680.png",
      "bytes": 90224,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-f604735557d19949c823.png",
      "src": "https://substackcdn.com/image/fetch/$s_!-lkw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffea460ea-84d5-4973-9bc7-dc0e53a13ae0_1340x680.png",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!F-dk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46d7a6f-fbd6-4783-8b5c-0a0bc39f5412_1582x330.png",
      "bytes": 53318,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-b7220d32d9ebeea547f2.png",
      "src": "https://substackcdn.com/image/fetch/$s_!F-dk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa46d7a6f-fbd6-4783-8b5c-0a0bc39f5412_1582x330.png",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!QahZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4063347e-8920-40c6-86b3-c520084b303c_1272x998.jpeg",
      "bytes": 121450,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-e341f96e7047c423362d.jpeg",
      "src": "https://substackcdn.com/image/fetch/$s_!QahZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4063347e-8920-40c6-86b3-c520084b303c_1272x998.jpeg",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!yNIB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa505c654-5ddf-485f-90a8-b656d03b94dc_2394x834.png",
      "bytes": 135395,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-a738c56ddbe64aac38c5.png",
      "src": "https://substackcdn.com/image/fetch/$s_!yNIB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa505c654-5ddf-485f-90a8-b656d03b94dc_2394x834.png",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!tQ_o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae8e84db-16f9-485d-a0cb-0392fc8aca56_1454x536.png",
      "bytes": 22613,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-9a2ad04d421db1e805c6.png",
      "src": "https://substackcdn.com/image/fetch/$s_!tQ_o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae8e84db-16f9-485d-a0cb-0392fc8aca56_1454x536.png",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!dyzC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6088451d-43e7-43a7-a615-270b1867cfea_1814x1316.png",
      "bytes": 146038,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-26127bbced803d761e2f.png",
      "src": "https://substackcdn.com/image/fetch/$s_!dyzC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6088451d-43e7-43a7-a615-270b1867cfea_1814x1316.png",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!X3Sv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89599158-c5bf-4e73-9d31-a388b625e4d2_2262x622.png",
      "bytes": 74484,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-3f845c82067ee8023a63.png",
      "src": "https://substackcdn.com/image/fetch/$s_!X3Sv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89599158-c5bf-4e73-9d31-a388b625e4d2_2262x622.png",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!4SpI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dfa415c-da9c-4d6f-8de8-ffc9f92272db_1602x952.png",
      "bytes": 191676,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-e427488e1361fea0ec58.png",
      "src": "https://substackcdn.com/image/fetch/$s_!4SpI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dfa415c-da9c-4d6f-8de8-ffc9f92272db_1602x952.png",
      "alt": "",
      "downloaded": true
    },
    {
      "status": "ok",
      "url": "https://substackcdn.com/image/fetch/$s_!CxIZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27b6d27d-1052-4a4f-a419-a69cdd36704a_1118x454.png",
      "bytes": 77779,
      "reused": false,
      "local_path": "attachments/54531b58b406/images/body-4095da258ac44040a4a6.png",
      "src": "https://substackcdn.com/image/fetch/$s_!CxIZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27b6d27d-1052-4a4f-a419-a69cdd36704a_1118x454.png",
      "alt": "",
      "downloaded": true
    }
  ],
  "audio": [],
  "videos": [],
  "links": [
    {
      "href": "https://d4mucfpksywv.cloudfront.net/better-language-models/language_models_are_unsupervised_multitask_learners.pdf",
      "label": "Radford et al.",
      "type": "a"
    },
    {
      "href": "https://arxiv.org/abs/2005.14165",
      "label": "Brown et al.",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!-lkw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffea460ea-84d5-4973-9bc7-dc0e53a13ae0_1340x680.png",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!QahZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4063347e-8920-40c6-86b3-c520084b303c_1272x998.jpeg",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!yNIB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa505c654-5ddf-485f-90a8-b656d03b94dc_2394x834.png",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://arxiv.org/abs/1810.04805",
      "label": "Devlin et al. 2018",
      "type": "a"
    },
    {
      "href": "https://github.com/rasbt/LLM-finetuning-scripts/tree/main/conventional/distilbert-movie-review",
      "label": "here",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!tQ_o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae8e84db-16f9-485d-a0cb-0392fc8aca56_1454x536.png",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://ai.stanford.edu/~amaas/data/sentiment/",
      "label": "IMDB movie review dataset",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!dyzC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6088451d-43e7-43a7-a615-270b1867cfea_1814x1316.png",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://github.com/rasbt/LLM-finetuning-scripts/tree/main/conventional/distilbert-movie-review/layerwise-experiment",
      "label": "here on GitHub",
      "type": "a"
    },
    {
      "href": "https://arxiv.org/abs/2303.15647",
      "label": "Lialin et al.",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!X3Sv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89599158-c5bf-4e73-9d31-a388b625e4d2_2262x622.png",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://arxiv.org/abs/2203.02155",
      "label": "Ouyang et al.",
      "type": "a"
    },
    {
      "href": "https://arxiv.org/abs/1707.06347",
      "label": "Schulman et al.",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!4SpI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dfa415c-da9c-4d6f-8de8-ffc9f92272db_1602x952.png",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://magazine.sebastianraschka.com/subscribe",
      "label": "paid subscription",
      "type": "a"
    },
    {
      "href": "https://sebastianraschka.com/books",
      "label": "one of my books",
      "type": "a"
    },
    {
      "href": "https://substackcdn.com/image/fetch/$s_!CxIZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27b6d27d-1052-4a4f-a419-a69cdd36704a_1118x454.png",
      "label": "",
      "type": "a"
    },
    {
      "href": "https://www.amazon.com/Machine-Learning-PyTorch-Scikit-Learn-scikit-learn-ebook-dp-B09NW48MR1/dp/B09NW48MR1/",
      "label": "Machine Learning with PyTorch and Scikit-Learn",
      "type": "a"
    },
    {
      "href": "https://nostarch.com/machine-learning-and-ai-beyond-basics",
      "label": "Machine Learning Q and AI",
      "type": "a"
    },
    {
      "href": "http://mng.bz/M96o",
      "label": "Build a Large Language Model (from Scratch)",
      "type": "a"
    }
  ],
  "repair_version": 2,
  "repaired_at": "2026-10-14T10:47:24Z",
  "source_url": "https://magazine.sebastianraschka.com/p/finetuning-large-language-models",
  "papers": [
    {
      "status": "download_error",
      "url": "https://d4mucfpksywv.cloudfront.net/better-language-models/language_models_are_unsupervised_multitask_learners.pdf",
      "reason": "ConnectionError: HTTPSConnectionPool(host='d4mucfpksywv.cloudfront.net', port=443): Max retries exceeded with url: /better-language-models/language_models_are_unsupervised_multitask_learners.pdf (C",
      "retried_at": "2026-10-20T22:23:44Z"
    },
    {
      "status": "ok",
      "url": "https://arxiv.org/pdf/2005.14165",
      "bytes": 6768044,
      "reused": true,
      "local_path": "papers/repair/0c1629d8d07d676c2aae.pdf"
    },
    {
      "status": "ok",
      "url": "https://arxiv.org/pdf/1810.04805",
      "bytes": 775166,
      "reused": false,
      "local_path": "papers/repair/33769e0bafc9f0c73baa.pdf"
    },
    {
      "status": "ok",
      "url": "https://arxiv.org/pdf/2303.15647",
      "bytes": 1697737,
      "reused": false,
      "local_path": "papers/repair/66f57b1fa256190f7112.pdf"
    },
    {
      "status": "ok",
      "url": "https://arxiv.org/pdf/2203.02155",
      "bytes": 1797405,
      "reused": true,
      "local_path": "papers/repair/4b8cf107df7118e0ffe8.pdf"
    },
    {
      "status": "ok",
      "url": "https://arxiv.org/pdf/1707.06347",
      "bytes": 2923532,
      "reused": true,
      "local_path": "papers/repair/5c73fa759d96331836bf.pdf"
    }
  ],
  "actual_video_files": [],
  "body_chars": 15698,
  "expected_body_images": 9,
  "discovery_status": "ok",
  "delivery_status": "partial",
  "missing_reason": "download_error",
  "raw_html": "attachments/54531b58b406/pages/source.html",
  "local_html": "attachments/54531b58b406/pages/article.html",
  "body_base_path": "attachments/54531b58b406/pages/",
  "body_markdown_path": "attachments/54531b58b406/pages/article.md"
}