Llama 3.2 3B — LoRA Fine-Tuned for Financial Sentiment Classification

A LoRA adapter fine-tuned on meta-llama/Llama-3.2-3B-Instruct to classify the sentiment of financial text (news headlines, filings excerpts, analyst commentary) as negative, neutral, or positive.

Model Details

Intended Use

Classify the sentiment of short financial text snippets (headlines, filing excerpts, earnings commentary) into negative/neutral/positive. Intended as a portfolio/research project, not a production financial decision-making tool — see Limitations below.

Prompt format the model was trained on:

What is the sentiment of this text? Please choose an answer from {negative/neutral/positive}.
 
Text: <your financial text here>
Sentiment:

Training Data

  • Dataset: FinGPT/fingpt-sentiment-train
  • Label collapsing: the source dataset mixes a 3-class and a 7-class (strong/moderately/mildly negative/positive) label granularity depending on which instruction template was used per row. All labels were collapsed to a consistent 3-class scheme (negative/neutral/positive) to make use of the full dataset rather than discarding the 7-class rows.
  • Deduplication: exact duplicate input texts were dropped.
  • Split: stratified 80/10/10 train/validation/test split (stratified on label, random_state=24).
  • Train set size: 30235

Training Procedure

LoRA Configuration

Parameter Value
r (rank) 16
lora_alpha 32
lora_dropout 0.05
target_modules q_proj, k_proj, v_proj, o_proj
bias none
task_type CAUSAL_LM

Training Configuration

Parameter Value
Epochs 3
Per-device batch size 4
Gradient accumulation steps 4
Effective batch size 16
Learning rate 2e-4
Max sequence length 512
Precision bf16, 4-bit quantized base (NF4)
Loss Completion-only (completion_only_loss=True in SFTConfig) — loss computed only on the label tokens, not the prompt
Framework 🤗 trl SFTTrainer

Hardware

Single Google Colab T4 GPU, ~143 minutes total training time

Evaluation

Evaluated on a held-out test set (10% of the deduplicated, label-collapsed dataset), untouched until final evaluation. The same evaluation function and prompt format were used for both the zero-shot baseline and the fine-tuned model, so results are directly comparable.

Metric Zero-shot baseline Fine-tuned Δ
Accuracy 0.293 0.805 +0.511
F1 (macro) 0.232 0.789 +0.557
F1 (weighted) 0.202 0.801 +0.599

Why macro F1 matters here: the dataset is imbalanced toward "neutral" labels, so accuracy alone can hide poor performance on the minority negative/positive classes. Macro F1 weights all three classes equally and is the more honest metric for this task.

Limitations

  • Trained and evaluated only on English-language financial text; performance on other languages or domains (general news, social media outside finance) is untested.
  • The label-collapsing step from 7-class to 3-class discards intensity information (e.g. "strongly negative" vs "mildly negative" are treated identically) — this simplifies the task but loses nuance the original annotators captured.
  • Sentiment labels reflect the tone/framing of the text, not a prediction of actual market movement or investment recommendation. This model should not be used as the sole basis for financial decisions.
  • Generated outputs are parsed via keyword matching (negative/neutral/positive substring search); unparseable generations default to "neutral," which may slightly understate error rates on edge cases.

How to Use

from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel
import torch
 
base_model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-3B-Instruct", torch_dtype=torch.bfloat16, device_map="auto"
)
model = PeftModel.from_pretrained(base_model, "benchaffe/llama3.2-3b-lora-financial-sentiment")
tokenizer = AutoTokenizer.from_pretrained("benchaffe/llama3.2-3b-lora-financial-sentiment")
 
prompt = (
    "What is the sentiment of this text? "
    "Please choose an answer from {negative/neutral/positive}.\n\n"
    "Text: Q3 revenue beat analyst expectations by 12%.\nSentiment:"
)
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
output = model.generate(**inputs, max_new_tokens=5, do_sample=False)
print(tokenizer.decode(output[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))

Citation

If you use this model, please also cite the base model and training dataset:

Base model: meta-llama/Llama-3.2-3B-Instruct
Training dataset: FinGPT/fingpt-sentiment-train
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for benchaffe/llama3.2-3b-lora-financial-sentiment

Adapter
(845)
this model

Dataset used to train benchaffe/llama3.2-3b-lora-financial-sentiment