{"id":1097,"date":"2026-09-09T05:59:10","date_gmt":"2026-09-09T05:59:10","guid":{"rendered":"https:\/\/x.sheep-mine.ts.net\/index.php\/how-to-fine-tune-llama-2-using-sft-lora\/"},"modified":"2026-09-09T05:59:10","modified_gmt":"2026-09-09T05:59:10","slug":"how-to-fine-tune-llama-2-using-sft-lora","status":"publish","type":"post","link":"https:\/\/x.sheep-mine.ts.net\/index.php\/how-to-fine-tune-llama-2-using-sft-lora\/","title":{"rendered":"How to fine-tune LLaMA 2 using SFT, LORA \u2013 Accubits Blog"},"content":{"rendered":"<p><br \/>\n<\/p>\n<div>\n<p class=\"wp-block-paragraph\">LLaMA 2 is finally here, and it doesn\u2019t disappoint. The new model has substantial performance improvements over its predecessor and comes with the added perk of being commercially usable. As enthusiasts and developers scramble to get their hands on this powerful tool, many are eager to fine-tune LLAMA2 for various applications. In this article, we\u2019ll learn <strong>how to fine-tune LLaMA2<\/strong> using two exceptional techniques: SFT (Supervised Fine-Tuning for full parameter) and LORA (Low-rank adaptation).<\/p>\n<h2 class=\"wp-block-heading\" id=\"A-quick-overview-of-llama-2\"><strong>A Quick Overview<\/strong> <strong>of LLaMA 2<\/strong><\/h2>\n<p class=\"wp-block-paragraph\"><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/about.fb.com\/news\/2023\/07\/llama-2\/\" target=\"_blank\" rel=\"noreferrer noopener\">Llama 2<\/a> is a collection of pretrained and fine-tuned LLMs ranging from 7 billion to 70 billion parameters. The model architecture is similar to LLaMA 1, with increased context length and the addition of <strong>Grouped Query Attention<\/strong> (GQA) to improve inference scalability. GQA is a standard practice for autoregressive decoding to cache the key and value pairs for the previous tokens in the sequence, speeding up attention computation. Other notable points are;<\/p>\n<ul class=\"wp-block-list\">\n<li>Trained on 2 trillion tokens of data<\/li>\n<li>Increased context length of 4K<\/li>\n<li>Uses a new method for multi-turn consistency, <strong>Ghost Attention<\/strong> (GAtt)<\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\">LLaMA 2 Benchmark<\/h3>\n<p class=\"wp-block-paragraph\">Llama 2 models outperform Llama 1 models. In particular, Llama 2 70B improves the results on MMLU and BBH by \u22485 and \u22488 points, respectively, compared to Llama 1 65B. Llama 2 7B and 30B models outperform MPT models of the corresponding size in all categories besides code benchmarks. For the Falcon models, Llama 2 7B and 34B outperform Falcon 7B and 40B models on all categories of benchmarks. Additionally, Llama 2 70B model outperforms all open-source models.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-1024x424.png\" alt=\"\" class=\"wp-image-19913\" width=\"700\" srcset=\"https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-1024x424.png 1024w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-300x124.png 300w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-768x318.png 768w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-1536x636.png 1536w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-830x344.png 830w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-550x228.png 550w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-230x95.png 230w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark.png 1846w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"\/><\/figure>\n<\/div>\n<p class=\"wp-block-paragraph\">When compared with closed-source LLMs, Llama 2 70B is close to GPT-3.5 on MMLU and GSM8K, but there is a significant gap in coding benchmarks. Llama 2 70B results are on par or better than PaLM (540B) on almost all benchmarks. There is still a large gap in performance between Llama 2 70B and GPT-4 and PaLM-2-L.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-1024x274.png\" alt=\"\" class=\"wp-image-19914\" width=\"600\" srcset=\"https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-1024x274.png 1024w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-300x80.png 300w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-768x205.png 768w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-1536x411.png 1536w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-830x222.png 830w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-550x147.png 550w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed-230x62.png 230w, https:\/\/blog.accubits.com\/wp-content\/uploads\/2023\/07\/LLAMA2-benchmark-againt-closed.png 1884w\" sizes=\"(max-width: 1024px) 100vw, 1024px\"\/><\/figure>\n<\/div>\n<h2 class=\"wp-block-heading\" id=\"How-to-fine-tune-Llama2-using-SFT\"><strong>How to fine-tune Llama2 using SFT<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">In this example, I explain the steps to fine-tune LLaMA 2 using Supervised fine-tuning (SFT). SFT fine-tunes an LLM in a supervised manner using examples of dialogue data that the model should replicate. The SFT dataset is a collection of prompts and their corresponding responses. SFT datasets can be manually curated by users or generated by other LLMs. To start the fine-tuning, the first step is to set up the development environment. <\/p>\n<p class=\"wp-block-paragraph\"><strong>Setup Development Environment<\/strong><\/p>\n<p class=\"wp-block-paragraph\">Install <em><strong>torch<\/strong><\/em> and <em><strong>transformers<\/strong><\/em> for PyTorch and the Hugging Face Transformers library, respectively, and <em>datasets<\/em> for loading and processing datasets.<\/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=\"\">!pip install \"transformers\"\n!pip install \"torch\"\n!pip install \"datasets\"\n!pip install \"peft\"<\/pre>\n<p class=\"wp-block-paragraph\"><strong>Load model and tokenizer<\/strong><\/p>\n<p class=\"wp-block-paragraph\">The script loads the base model and tokenizer for the Llama model from Hugging Face Transformers using the <em><strong>LlamaForCausalLM<\/strong><\/em> and <strong><em>LlamaTokenizer<\/em><\/strong> classes.<\/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=\"\">model = LlamaForCausalLM.from_pretrained(\n        base_model,\n        # load_in_8bit=True, # Add this for using int8\n        torch_dtype=torch.float16,\n        device_map=device_map,\n    )\n\u200b\n    tokenizer = LlamaTokenizer.from_pretrained(base_model)\n    tokenizer.pad_token_id = 0\n<\/pre>\n<p class=\"wp-block-paragraph\"><strong>Load data<\/strong><\/p>\n<p class=\"wp-block-paragraph\">Dataset loading is based on the file format specified by the data_path argument. load a dataset either from a JSON or JSON Lines file (specified by the data_path argument as a file path) or from a dataset available in the Hugging Face datasets library (specified by the data_path argument as a dataset name). The loaded dataset is stored in the data variable, which can then be further processed and tokenized for model training.<\/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=\"\">    if data_path.endswith(\".json\") or data_path.endswith(\".jsonl\"):\n        data = load_dataset(\"json\", data_files=data_path)\n    else:\n        data = load_dataset(data_path)\n<\/pre>\n<p class=\"wp-block-paragraph\"><strong>Tokenize data<\/strong><\/p>\n<p class=\"wp-block-paragraph\">The <em><strong>tokenize()<\/strong><\/em> function is defined to preprocess the data. It encodes the input and output text data into token IDs, concatenates them, and appends an end-of-sequence token. The encoded data is then prepared as input for the model. The data is split into training and validation sets using the <strong><em>train_test_split()<\/em><\/strong> function from the datasets library.<\/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=\"\">def tokenize(data):\n        source_ids = tokenizer.encode(data['input'])\n        target_ids = tokenizer.encode(data['output'])\n\u200b\n        input_ids = source_ids + target_ids + [tokenizer.eos_token_id]\n        labels = [-100] * len(source_ids) + target_ids + [tokenizer.eos_token_id]\n\u200b\n        return {\n            \"input_ids\": input_ids,\n            \"labels\": labels\n        }\n\u200b\n#split thte data to train\/val set\ntrain_val = data[\"train\"].train_test_split(\n    test_size=val_set_size, shuffle=False, seed=42\n)\ntrain_data = (\n    train_val[\"train\"].shuffle().map(tokenize)\n)\nval_data = (\n    train_val[\"test\"].shuffle().map(tokenize)\n        \n)\n<\/pre>\n<p class=\"wp-block-paragraph\"><strong><em>input_ids<\/em><\/strong> are created by concatenating the token IDs of the source and target text, followed by the EOS token ID. This forms the input sequence for the language model during training. Given the input, the model will be trained to predict the target sequence.<\/p>\n<p class=\"wp-block-paragraph\"><strong><em>labels<\/em><\/strong> are created by concatenating the list of -100 values (for the source text), followed by the token IDs of the target text, and finally, the EOS token ID. This labels list serves as the target labels for the language model during training. The model will be trained to predict the target sequence (token IDs in the labels) from the input sequence (token IDs in the input_ids).<\/p>\n<p class=\"wp-block-paragraph\"><strong>[-100] * len(source_ids)<\/strong>: This creates a list of -100 values with a length equal to the number of tokens in the source text. The value -100 is a special value used to mask tokens that do not require predicting (i.e., padding tokens).<\/p>\n<p class=\"wp-block-paragraph\"><strong>Initiate the trainer<\/strong><\/p>\n<p class=\"wp-block-paragraph\">The script creates a <strong><em>transformers.Trainer object<\/em><\/strong> for training the model. It uses the <strong><em>train_data<\/em><\/strong> and <strong><em>val_data<\/em><\/strong> datasets and various training configurations such as batch size, gradient accumulation steps, number of epochs, learning rate, etc.<\/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=\"\">   trainer = transformers.Trainer(\n        model=model,\n        train_dataset=train_data,\n        eval_dataset=val_data,\n        args=transformers.TrainingArguments(\n            per_device_train_batch_size=micro_batch_size,\n            gradient_accumulation_steps=gradient_accumulation_steps,\n            warmup_steps=100,\n            num_train_epochs=num_epochs,\n            learning_rate=learning_rate,\n            fp16=True,\n            logging_steps=10,\n            optim=\"adamw_torch\",\n            evaluation_strategy=\"steps\",\n            save_strategy=\"steps\",\n            eval_steps=200,\n            save_steps=200,\n            output_dir=output_dir,\n            save_total_limit=3\n        ),\n        data_collator=transformers.DataCollatorForSeq2Seq(\n            tokenizer, pad_to_multiple_of=8, return_tensors=\"pt\", padding=True\n        ),\n    )\n\u200b\n    trainer.train()<\/pre>\n<p class=\"wp-block-paragraph\"><strong>Save Model<\/strong><\/p>\n<p class=\"wp-block-paragraph\">After training, the final model is saved to the specified <strong><em>output_dir<\/em><\/strong>. <\/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=\"\">   model.save_pretrained(output_dir)\n<\/pre>\n<p class=\"wp-block-paragraph\"><strong>Run Model<\/strong><\/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=\"\">python train.py --base_model meta-llama\/Llama-2-7b --data_path tatsu-lab\/alpaca --output_dir output\/<\/pre>\n<h2 class=\"wp-block-heading\" id=\"How-to-fine-tune-Llama2-using-LORA\"><strong>How to fine-tune Llama2 using LORA<\/strong><\/h2>\n<p class=\"wp-block-paragraph\">Here, I explain the steps to fine-tune LLaMA 2 in this example using Low-Rank Adaptation (LoRA). LoRA proposes to freeze pre-trained model weights and inject trainable layers (rank-decomposition matrices) in each transformer block. This greatly reduces the number of trainable parameters and GPU memory requirements since gradients don\u2019t need to be computed for most model weights.<\/p>\n<p class=\"wp-block-paragraph\"> The steps to fine-tune LLaMA 2 using LoRA is the same as of SFT. In the code, when loading the model and tokenizer, you need to specify the LoRA parameters. A sample code for fine-tuning LLaMA2 with LoRA is provided below. <\/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 typing import List\n\u200b\nimport fire\nimport torch\nimport transformers\nfrom datasets import load_dataset\n\u200b\n\u200b\nfrom peft import (\n    LoraConfig,\n    get_peft_model,\n    get_peft_model_state_dict,\n    prepare_model_for_int8_training,\n    set_peft_model_state_dict,\n    PrefixTuningConfig,\n    TaskType\n)\nfrom transformers import LlamaForCausalLM, LlamaTokenizer\n\u200b\n\u200b\n\u200b\ndef train(\n    # model\/data params\n    base_model: str = \"\", \n    data_path: str = \"\",\n    output_dir: str = \"\",\n\u200b\n    micro_batch_size: int = 4,\n    gradient_accumulation_steps: int = 4,\n    num_epochs: int = 3,\n    learning_rate: float = 3e-4,\n    val_set_size: int = 2000,\n    \n    # lora hyperparams\n    lora_r: int = 8,\n    lora_alpha: int = 16,\n    lora_dropout: float = 0.05,\n    lora_target_modules: List[str] = [\n        \"q_proj\",\n        \"v_proj\",\n    ]\n):\n\u200b\n    device_map = \"auto\"\n\u200b\n\u200b\n    # Step 1: Load the model and tokenizer\n\u200b\n    model = LlamaForCausalLM.from_pretrained(\n        base_model,\n        # load_in_8bit=True, # Add this for using int8\n        torch_dtype=torch.float16,\n        device_map=device_map,\n    )\n\u200b\n    tokenizer = LlamaTokenizer.from_pretrained(base_model)\n    tokenizer.pad_token_id = 0\n\u200b\n      Add this for training LoRA\n\u200b\n      config = LoraConfig(\n          r=lora_r,\n          lora_alpha=lora_alpha,\n          target_modules=lora_target_modules,\n          lora_dropout=lora_dropout,\n          bias=\"none\",\n          task_type=\"CAUSAL_LM\",\n      )\n      model = get_peft_model(model, config)\n\u200b\n      model = prepare_model_for_int8_training(model) # Add this for using int8\n\u200b\n\u200b\n    # Step 2: Load the data\n\u200b\n    if data_path.endswith(\".json\") or data_path.endswith(\".jsonl\"):\n        data = load_dataset(\"json\", data_files=data_path)\n    else:\n        data = load_dataset(data_path)\n    \n    # Step 3: Tokenize the data\n\u200b\n    def tokenize(data):\n        source_ids = tokenizer.encode(data['input'])\n        target_ids = tokenizer.encode(data['output'])\n\u200b\n        input_ids = source_ids + target_ids + [tokenizer.eos_token_id]\n        labels = [-100] * len(source_ids) + target_ids + [tokenizer.eos_token_id]\n\u200b\n        return {\n            \"input_ids\": input_ids,\n            \"labels\": labels\n        }\n\u200b\n    #split thte data to train\/val set\n    train_val = data[\"train\"].train_test_split(\n        test_size=val_set_size, shuffle=False, seed=42\n    )\n    train_data = (\n        train_val[\"train\"].shuffle().map(tokenize)\n    )\n    val_data = (\n        train_val[\"test\"].shuffle().map(tokenize)\n        \n    )\n\u200b\n    # Step 4: Initiate the trainer\n\u200b\n    trainer = transformers.Trainer(\n        model=model,\n        train_dataset=train_data,\n        eval_dataset=val_data,\n        args=transformers.TrainingArguments(\n            per_device_train_batch_size=micro_batch_size,\n            gradient_accumulation_steps=gradient_accumulation_steps,\n            warmup_steps=100,\n            num_train_epochs=num_epochs,\n            learning_rate=learning_rate,\n            fp16=True,\n            logging_steps=10,\n            optim=\"adamw_torch\",\n            evaluation_strategy=\"steps\",\n            save_strategy=\"steps\",\n            eval_steps=200,\n            save_steps=200,\n            output_dir=output_dir,\n            save_total_limit=3\n        ),\n        data_collator=transformers.DataCollatorForSeq2Seq(\n            tokenizer, pad_to_multiple_of=8, return_tensors=\"pt\", padding=True\n        ),\n    )\n\u200b\n    trainer.train()\n\u200b\n\u200b\n    # Step 5: save the model\n    model.save_pretrained(output_dir)\n\u200b\n\u200b\n\u200b\nif __name__ == \"__main__\":\n    fire.Fire(train)\n\n<\/pre>\n<p class=\"wp-block-paragraph\"><strong><em>LoraConfig<\/em><\/strong> is a class provided by the PeFT framework that allows you to configure the LoRA training process. The code shows how to create a <strong><em>LoraConfig<\/em><\/strong> object with the following parameters;<\/p>\n<p class=\"wp-block-paragraph\"><strong><em>r<\/em><\/strong>: the rank of the update matrices, expressed in int. Lower rank results in smaller update matrices with fewer trainable parameters.<br \/><strong><em>lora_alpha<\/em><\/strong>: LoRA scaling factor<br \/><strong><em>target_modules<\/em><\/strong>: The modules (for example, attention blocks) to apply the LoRA update matrices.<br \/><strong><em>bias<\/em><\/strong>: Specifies if the bias parameters should be trained. Can be \u2018none\u2019, \u2018all\u2019 or \u2018lora_only\u2019.<\/p>\n<p>The code further calls the <strong><em>get_peft_model()<\/em><\/strong> function to create a PeFT model by integrating the LoRA configurations into the base model. The result is assigned back to the model variable. The <strong><em>prepare_model_for_int8_training()<\/em><\/strong> function is applied to the model to enable int8 quantization. This function is part of the PeFT framework, and it prepares the model to be trained using 8-bit precision, which can help reduce the model\u2019s memory and computational footprint. <em>int8<\/em> quantization is an optimization technique and can be used to reduce memory usage during inference but does not affect the actual training process itself.<\/p>\n<\/p><\/div>\n<p><br \/>\n<br \/><a href=\"https:\/\/blog.accubits.com\/how-to-fine-tune-llama-2-using-sft-lora\/\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>LLaMA 2 is finally here, and it doesn\u2019t disappoint. The new model has substantial performance&#8230;<\/p>\n","protected":false},"author":1,"featured_media":1098,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1794,2205],"tags":[],"class_list":["post-1097","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-artificial-intelligence","category-llm"],"_links":{"self":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts\/1097","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/comments?post=1097"}],"version-history":[{"count":0,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/posts\/1097\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/media\/1098"}],"wp:attachment":[{"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/media?parent=1097"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/categories?post=1097"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/x.sheep-mine.ts.net\/index.php\/wp-json\/wp\/v2\/tags?post=1097"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}