← All projects

Case study · Generative AI

Fine-Tuning LLaMA-2 7B for Python Code Generation

A resource-efficient path from noisy training data to local inference
QLoRAHumanEvalAugust 2026

Executive summary

Can a general model become a useful local coding model?

Challenge

Improve Python generation without the memory cost of full-parameter fine-tuning or dependence on a cloud API.

Approach

Distill 60,000 raw samples to 13,914 functional examples, then fine-tune 4-bit LLaMA-2 7B Chat with QLoRA.

Evidence

Pass@1 rose 10.4% and Pass@5 rose 19.4% relative to the untuned chat model; local inference reached 15.67 tokens/s.

Boundary

The result improves the chosen base model but remains well behind CodeLlama, showing the limit of task adaptation without code-specific pretraining.

1. Problem & Constraint

Large Language Models have transformed software development, but their scaling creates a deployment barrier: high-performing models require substantial GPU memory and are commonly accessed through cloud APIs. For students, researchers, and small teams, cloud-only access introduces cost, latency, privacy concerns, and external dependence.

Smaller open models like LLaMA-2 7B can run on consumer GPUs, but their code-generation quality is weaker than that of larger or code-specialized models. This motivates methods that adapt smaller models to specialized tasks without full parameter fine-tuning.

Parameter-Efficient Fine-Tuning (PEFT) provides a practical solution. LoRA injects low-rank trainable matrices into transformer layers, reducing trainable parameter count. QLoRA extends this by quantizing the base model to 4-bit precision and training LoRA adapters on top, enabling 7B-scale adaptation on modest hardware.

The project objective was deliberately practical: improve executable Python generation enough to measure a gain over the untuned chat model, then package the result for responsive local inference on a consumer GPU.

7B
Parameters
<1%
Trainable Params
4-bit
Quantization
5.1 GB
Peak VRAM

2. Data Collection & Curation

Source Datasets

DatasetRaw SizeDescriptionLicense
FlyTech Python Code~42,000 pairsPython scripts with comments, docstrings, structured tasksMIT
Python Code Instructions 18k (Alpaca-style)~18,000 pairsInstruction prompts and Python responsesCC BY-NC 4.0

Filtering Pipeline

The raw datasets contained general scripting tasks, web-development snippets, machine-learning examples, duplicates, empty descriptions, comments, docstrings, and non-functional fragments. We applied a multi-stage filtering pipeline:

Stage 1 — Teacher-Model Classification: Used qwen2.5-coder:1.5b to identify algorithmic and logic-oriented tasks from the Alpaca-style dataset, flagging ~12,000 relevant samples. Manual audit removed false positives.
Stage 2 — Null/Empty Removal: From FlyTech, removed rows with null or empty descriptions, reducing from ~42,000 to 9,616 higher-quality candidates.
Stage 3 — Duplicate & Length Filtering: Removed very short samples (incomplete functions, trivial fragments) and duplicate entries.
Stage 4 — Repetition-Ratio Filtering: Discarded samples with repetition ratio rho > 0.4, where rho = 1.0 - (unique tokens / total tokens). High repetition corresponded to boilerplate or circular logic.
Stage 5 — Functional-Code Cleaning: Removed comments, docstrings, and non-functional code to reduce natural-language leakage and encourage the model to learn executable logic.

Impact of Repetition Threshold

Max Repetition Ratio (rho)Final Dataset Size
0.720,335
0.620,270
0.519,876
0.4 (selected)18,487
0.315,577

Dataset Distillation Summary

StageSample CountLogic Density
Raw Combined60,000Low
Filtered (Logic Only)34,000Medium
Refined (Functional/Clean)21,542High
Final (Functional Only)13,914Very High

Why This Matters

The curation pipeline was designed to concentrate the training signal on executable Python rather than comments, repeated boilerplate, or incomplete fragments. The project did not independently ablate every filtering stage, so its individual causal contribution should not be inferred from the final benchmark gain.

3. Methodology

Key Pivot: Base Model to Chat Model

An initial base-model strategy produced inconsistent output structure and weak task alignment, which made Pass@k evaluation noisy. Moving to LLaMA-2 Chat forced a clearer instruction template and stable response boundary. The pivot was less about choosing a fashionable model and more about making outputs easier to execute, compare, and score.

Prompt Formatting

All examples were converted into the LLaMA-2 native instruction format using the chat template with [INST] markers. The tokenizer maximum length was set to 512 tokens with right-side padding, and the padding token was mapped to the end-of-sequence token so the model could learn clear termination behavior during generation.

Completion-Only Instruction Masking

Standard supervised fine-tuning can compute loss over every token in the prompt-response sequence. Here, tokens belonging to the instruction and template prefix were assigned the label -100, which PyTorch cross-entropy ignores. This aligned the optimization objective with the response tokens after the [/INST] marker instead of spending loss on reproducing the prompt.

Hyperparameter Optimization

We performed hyperparameter optimization with Optuna using a reduced 5% subset of the training data. Each trial used an 80/20 train-validation split. We ran 45 trials with Tree-structured Parzen Estimator search and pruning for underperforming trials.

HyperparameterOptimal Value
Learning Rate2.9089 x 10^-5
LR SchedulerCosine
LoRA Rank (r)8
LoRA Alpha32
LoRA Dropout0.0961
Batch Size4
Warmup Ratio0.0693

QLoRA Fine-Tuning

The pretrained LLaMA-2 7B Chat weights were loaded in 4-bit NormalFloat format with double quantization. LoRA adapters were inserted into attention and feed-forward decoder modules while keeping the original base-model weights frozen. Only adapter parameters were trainable, representing less than 1% of total model parameters.

Training was performed on Kaggle dual-T4 GPUs using cross-entropy loss on response tokens only. Training was stopped during the second epoch because validation loss continued to decrease only marginally (below ~0.001), reducing overfitting risk.

Hardware & Infrastructure

Data preparation: Kaggle/Colab CPU or T4 GPU. HPO: Kaggle dual-T4 or P100. Final fine-tuning: Kaggle dual-T4 GPUs. Local inference: Ollama on RTX 3060/4060-class GPU.

Diagram of the LLaMA decoder architecture with QLoRA adapters in attention and feed-forward layers
QLoRA adapters inside the LLaMA-2 decoder stack

4. Results

Quantization Impact

Model FormatMemory UsageRelative Change
FP1628 GB
4-bit NF45.2 GB81.4% reduction

Quantization substantially reduced memory requirements. The 81.4% memory reduction enabled full training and deployment workflow without large data-center GPUs. We observed only a small quantitative performance difference between non-quantized and quantized inference.

HumanEval Pass@k Comparison

MetricUntuned LLaMA-2 7B ChatFine-Tuned ModelCodeLlama
Pass@10.11590.12800.2915
Pass@30.16100.19270.4683
Pass@50.18900.22560.5159
Relative improvements over base model: Pass@1 +10.4%, Pass@3 +19.7%, Pass@5 +19.4%
Gap to CodeLlama: The fine-tuned model improves on untuned LLaMA-2 7B Chat but does not approach a model whose pretraining distribution is already optimized for code.

BLEU & CodeBLEU

MetricScore
BLEU10.2703
CodeBLEU0.2363

BLEU remained limited because many programming problems permit multiple correct implementations with different surface forms. CodeBLEU is more informative because it considers code structure, syntax, and data-flow. Functional testing (HumanEval) remains the more important criterion for code generation.

Local Ollama Inference

MetricValue
Time to First Token0.52 seconds
Average Generation Speed15.67 tokens/s
Peak VRAM Usage5.1 GB
HardwareNVIDIA RTX 4050
+10.4%
Pass@1 Gain
+19.4%
Pass@5 Gain
81.4%
Memory Reduction
15.67
Tokens/Second

Evaluation Evidence

5. Limitations

Limited dataset scope. The final dataset focuses on Python and algorithmic tasks. It does not cover the full diversity of real software engineering work (web frameworks, data pipelines, concurrent programming, etc.).

Metrics cannot guarantee correctness. BLEU and CodeBLEU measure surface similarity, not functional correctness. A syntactically similar solution can still fail hidden test cases.

Narrow functional evaluation. HumanEval contains only 164 problems and may not represent broader production scenarios. More diverse benchmarks (MBPP, SWE-bench) would provide a fuller picture.

Fine-tuning cannot replace code-specific pretraining. The fine-tuned model remains significantly below CodeLlama on HumanEval, indicating that task-specific QLoRA improves LLaMA-2 but cannot fully compensate for limited code-specific pretraining.

Single-language deployment. Deployment was tested for Python code generation only and was not extended to multilingual code generation.

No component ablation. The final gain reflects the complete pipeline—data curation, prompt format, masking, hyperparameters, and QLoRA—not a controlled estimate of any one component's contribution.

The defensible conclusion is that parameter-efficient adaptation improved this base model within the measured task and hardware envelope—not that it produced a production-grade coding assistant.

6. Practical Recommendations

For teams considering similar fine-tuning projects on constrained hardware:

Priority 1 — High Confidence

Invest heavily in data curation

Signal: The largest operational change was reducing 60,000 raw samples to 13,914 higher-density functional examples through teacher-model filtering and heuristic cleaning.

Action: Always clean before training. Remove comments, docstrings, duplicates, and repetitive boilerplate. Quality matters more than quantity.

Confidence: Medium — the filtering stages were not isolated in a controlled ablation
Priority 1 — High Confidence

Use completion-only instruction masking

Signal: Masking the prompt forces the loss function to focus on the code response rather than the instruction template.

Action: Apply -100 labels to all prompt tokens. This is a simple change with consistent benefits for instruction-tuned models.

Confidence: Medium — objective alignment is clear, but this project did not independently ablate masking
Priority 2 — High Confidence

Use QLoRA for hardware-constrained projects

Signal: 4-bit NF4 quantization reduced measured memory from 28 GB to 5.2 GB, while the complete fine-tuning pipeline improved HumanEval results over the untuned model.

Action: Use NormalFloat4 quantization with double quantization and paged optimizers. LoRA rank 8 with alpha 32 is a strong starting configuration.

Confidence: High — well-supported by both our results and the broader QLoRA literature
Priority 3 — Medium Confidence

Optimize hyperparameters on a data subset

Signal: Optuna with 45 trials on 5% of training data found effective configurations at low compute cost.

Action: Use Tree-structured Parzen Estimator search with early pruning. Focus search on learning rate, LoRA rank, dropout, and warmup ratio.

Confidence: Medium — optimal hyperparameters may differ for other base models or tasks

What NOT to do

Do not skip data cleaning in favor of larger datasets. Do not compute loss over prompt tokens when fine-tuning instruction-tuned models. Do not expect fine-tuning alone to match code-specialized pretrained models like CodeLlama.

7. Reproducibility

Environment: Python 3.10+, PyTorch, Hugging Face Transformers, PEFT, bitsandbytes, Optuna, Kaggle dual-T4 GPUs.

Base model: meta-llama/Llama-2-7b-chat-hf (4-bit NF4 quantized).

Evaluation: HumanEval (164 Python problems), BLEU, CodeBLEU.

Deployment: Ollama local inference on consumer NVIDIA GPU.

8. Future Work