Skip to content
<konstantinos/>
Back to blog

Article

Running and Training Local LLMs: A Complete Guide

12 min read Permalink

In the rapidly evolving landscape of artificial intelligence, having the ability to run and train Large Language Models (LLMs) locally has become increasingly important. This comprehensive guide will walk you through setting up LM Studio to run pre-trained models locally and then explain how to train your own LLM.

Part 1: Setting Up LM Studio for Local LLM Inference

What is LM Studio?

LM Studio is a powerful desktop application that allows you to download, manage, and run various open-source large language models on your local machine. It provides a user-friendly interface for running inference without requiring deep technical knowledge.

System Requirements

Before installing LM Studio, ensure your system meets these minimum requirements:

  • Windows 10/11 64-bit or macOS 12+
  • 16GB RAM (32GB recommended)
  • Modern CPU with AVX2 support
  • NVIDIA GPU with 8GB VRAM (for GPU acceleration)
  • 20GB free storage space (varies based on model size)

Installation Steps

  1. Download LM Studio:
  • Visit the official LM Studio website
  • Choose the appropriate version for your operating system
  • Download and run the installer
  1. Initial Setup:
  • Launch LM Studio after installation
  • Select your preferred model storage location
  • Choose CPU or GPU inference mode based on your hardware
  1. Downloading Your First Model:
  • Click on the “Models” tab
  • Browse the available models (recommended starting models: Mistral 7B or Llama-2 7B)
  • Click “Download” for your chosen model
  • Wait for the download and conversion process to complete

Running Your First Local LLM

  1. Model Selection:
  • Navigate to the “Chat” tab
  • Select your downloaded model from the dropdown menu
  • Choose inference parameters:
    • Temperature: 0.7 (recommended for balanced output)
    • Top-P: 0.9
    • Max tokens: 2048
  1. Configuration:
  • Set context window size based on your model
  • Adjust system prompt if desired
  • Configure memory settings based on your hardware
  1. Testing:
  • Type a test prompt in the chat interface
  • Click “Send” or press Enter
  • Monitor resource usage through the built-in performance metrics

Best Practices for Local Inference

  • Start with smaller models (7B parameters) and gradually move to larger ones
  • Monitor system resources during inference
  • Use appropriate quantization for your hardware
  • Keep models updated through LM Studio’s update feature
  • Regularly clean up unused models to save space

Part 2: Training Your Own LLM

Prerequisites for Training

  • Python 3.8+ installed
  • NVIDIA GPU with 24GB+ VRAM (or cloud GPU access)
  • Basic understanding of machine learning concepts
  • Familiarity with command-line operations

Setting Up the Training Environment

  1. Create a new Python virtual environment:
python -m venv llm_training
source llm_training/bin/activate  # Linux/Mac
llm_training\Scripts\activate     # Windows
  1. Install required packages:
pip install torch transformers datasets accelerate wandb
  1. Prepare your training data:
  • Clean and format your dataset
  • Convert to appropriate format (usually JSON or CSV)
  • Split into training and validation sets

Training Process

  1. Choose Your Base Model:
  • Select a pre-trained model as starting point
  • Popular choices include:
  • Llama-2-7b
  • GPT-Neo
  • BLOOM
  • Mistral-7B
  1. Configure Training Parameters:

Before diving into the actual training process, it’s crucial to properly configure your training parameters. These parameters will significantly impact your model’s performance, training time, and resource usage.

First, let’s set up the complete training environment and parameters:

import torch
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    TrainingArguments,
    Trainer,
    DataCollatorForLanguageModeling
)
from datasets import load_dataset
import wandb

# Initialize wandb for experiment tracking (optional but recommended)
wandb.init(project="llm-training")

# Load the base model and tokenizer
model_name = "meta-llama/Llama-2-7b"  # Replace with your chosen base model
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

# Configure training parameters
training_args = TrainingArguments(
    # Basic Training Parameters
    output_dir="./results",                    # Directory to save model checkpoints
    num_train_epochs=3,                        # Total number of training epochs
    per_device_train_batch_size=4,             # Batch size per GPU/CPU for training
    per_device_eval_batch_size=4,              # Batch size per GPU/CPU for evaluation
    gradient_accumulation_steps=4,             # Number of updates steps to accumulate before backward pass

    # Learning Rate & Schedule
    learning_rate=2e-5,                        # Initial learning rate
    lr_scheduler_type="cosine",                # Learning rate schedule type
    warmup_ratio=0.1,                          # Percentage of steps for warmup

    # Optimization Parameters
    fp16=True,                                 # Enable mixed-precision training
    gradient_checkpointing=True,               # Enable gradient checkpointing to save memory
    max_grad_norm=1.0,                         # Maximum gradient norm for gradient clipping

    # Logging & Evaluation
    logging_dir="./logs",                      # Directory for storing logs
    logging_steps=100,                         # Log every X updates steps
    eval_steps=500,                            # Evaluate every X updates steps
    save_steps=500,                            # Save checkpoint every X updates steps
    save_total_limit=3,                        # Limit the total amount of checkpoints

    # Weight Decay & Regularization
    weight_decay=0.01,                         # Weight decay for AdamW optimizer

    # Report to wandb for tracking
    report_to=["wandb"],                       

    # Push to Hub (if you want to share your model)
    push_to_hub=False,                         # Enable pushing to Hugging Face Hub
    hub_model_id="your-username/model-name",   # Hugging Face Hub repository ID
)

# Configure the data collator
data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer,
    mlm=False  # Set to True for BERT-like models, False for GPT-like models
)

# Prepare your dataset
def prepare_dataset(examples):
    # Tokenize the texts with padding
    return tokenizer(
        examples["text"],
        truncation=True,
        padding="max_length",
        max_length=512  # Adjust based on your needs
    )

# Load and prepare your dataset
dataset = load_dataset('json', data_files={'train': 'train.json'})
tokenized_dataset = dataset.map(
    prepare_dataset,
    batched=True,
    remove_columns=dataset["train"].column_names
)

# Initialize the Trainer
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    data_collator=data_collator,
    tokenizer=tokenizer
)

Let’s break down each parameter and its importance:

Basic Training Parameters

  • output_dir: Where your model checkpoints will be saved
  • num_train_epochs: Total number of training epochs
  • per_device_train_batch_size: How many samples per batch on each GPU/CPU
  • gradient_accumulation_steps: Accumulate gradients over multiple steps to simulate larger batch sizes

Learning Rate & Schedule

  • learning_rate: Starting learning rate (2e-5 is a good default for fine-tuning)
  • lr_scheduler_type: “cosine” provides smooth learning rate decay
  • warmup_ratio: Gradually increase learning rate for stable training

Optimization Parameters

  • fp16: Enable mixed precision training to save memory and speed up training
  • gradient_checkpointing: Trade computation for memory savings
  • max_grad_norm: Prevent gradient explosions

Logging & Evaluation

  • logging_steps: How often to log training metrics
  • eval_steps: How often to run evaluation
  • save_steps: How often to save checkpoints
  • save_total_limit: Prevent storing too many checkpoints

Weight Decay & Regularization

  • weight_decay: L2 regularization to prevent overfitting

Using the Training Parameters

After configuration, you can start training with:

# Start training
trainer.train()

# Save the final model
trainer.save_model("./final-model")

# Push to Hugging Face Hub (if configured)
if training_args.push_to_hub:
    trainer.push_to_hub()

Monitoring Training Progress and Evaluation Metrics

Proper monitoring is crucial for successful LLM training. Here’s a comprehensive approach to monitoring and evaluation:

Key Metrics to Monitor

  1. Training Metrics:
# Set up comprehensive monitoring
training_args = TrainingArguments(
    # Previous parameters remain the same
    evaluation_strategy="steps",       # Run evaluation every eval_steps
    metric_for_best_model="loss",     # Metric to use for saving best model
    load_best_model_at_end=True,      # Load the best model when training ends
    greater_is_better=False,          # Lower loss is better

    # Add detailed logging
    logging_first_step=True,          # Log the first training step
    logging_steps=50,                 # Log every 50 steps
    log_level="info",                # Detailed logging level
)

# Custom logging function
def log_training_progress(trainer, metrics):
    """Log detailed training metrics"""
    wandb.log({
        "learning_rate": trainer.optimizer.param_groups[0]["lr"],
        "gradient_norm": metrics.get("gradient_norm", 0),
        "train_loss": metrics.get("loss", 0),
        "train_perplexity": torch.exp(torch.tensor(metrics.get("loss", 0))),
        "epoch": metrics.get("epoch", 0),
        "step": metrics.get("step", 0),
    })

# Add custom callback
class MetricsCallback(TrainerCallback):
    def on_log(self, args, state, control, logs=None, **kwargs):
        if state.is_local_process_zero and logs is not None:
            log_training_progress(trainer, logs)
  1. Evaluation Metrics:
def compute_metrics(eval_preds):
    """Compute custom evaluation metrics"""
    predictions, labels = eval_preds

    # Calculate perplexity
    perplexity = torch.exp(torch.tensor(trainer.state.log_history[-1]["eval_loss"]))

    # Calculate token accuracy
    predictions = np.argmax(predictions, axis=-1)
    accuracy = np.mean(predictions == labels)

    # Calculate ROUGE scores for text generation
    rouge = evaluate.load("rouge")
    rouge_scores = rouge.compute(
        predictions=tokenizer.batch_decode(predictions, skip_special_tokens=True),
        references=tokenizer.batch_decode(labels, skip_special_tokens=True)
    )

    return {
        "perplexity": perplexity.item(),
        "accuracy": accuracy,
        "rouge1": rouge_scores["rouge1"],
        "rouge2": rouge_scores["rouge2"],
        "rougeL": rouge_scores["rougeL"]
    }

# Add to trainer
trainer = Trainer(
    # Previous parameters remain the same
    compute_metrics=compute_metrics,
    callbacks=[MetricsCallback]
)

Visualizing Training Progress

import matplotlib.pyplot as plt
import seaborn as sns

def plot_training_progress(trainer):
    """Plot training metrics over time"""
    history = trainer.state.log_history

    # Create figure with multiple subplots
    fig, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 15))

    # Plot loss
    steps = [x["step"] for x in history if "loss" in x]
    losses = [x["loss"] for x in history if "loss" in x]
    ax1.plot(steps, losses)
    ax1.set_title("Training Loss")
    ax1.set_xlabel("Steps")
    ax1.set_ylabel("Loss")

    # Plot learning rate
    lrs = [x["learning_rate"] for x in history if "learning_rate" in x]
    ax2.plot(steps, lrs)
    ax2.set_title("Learning Rate")
    ax2.set_xlabel("Steps")
    ax2.set_ylabel("Learning Rate")

    # Plot perplexity
    perplexities = [torch.exp(torch.tensor(x["loss"])).item() for x in history if "loss" in x]
    ax3.plot(steps, perplexities)
    ax3.set_title("Perplexity")
    ax3.set_xlabel("Steps")
    ax3.set_ylabel("Perplexity")

    plt.tight_layout()
    plt.show()

Common Debugging Scenarios and Solutions

1. Out of Memory (OOM) Errors

# Problem: RuntimeError: CUDA out of memory
# Solution 1: Gradient Checkpointing
training_args = TrainingArguments(
    gradient_checkpointing=True,
    gradient_checkpointing_kwargs={"use_reentrant": False}
)

# Solution 2: Dynamic Padding
data_collator = DataCollatorForLanguageModeling(
    tokenizer=tokenizer,
    mlm=False,
    pad_to_multiple_of=8  # Optimize for tensor cores
)

# Solution 3: Memory-efficient attention
model.config.attention_implementation = "flash_attention_2"

2. Gradient Explosion/Vanishing

# Problem: Loss becoming NaN or inf
# Solution: Gradient Clipping and Loss Scaling
training_args = TrainingArguments(
    max_grad_norm=1.0,       # Clip gradients
    fp16=True,              # Use mixed precision
    fp16_opt_level="O2",    # Aggressive mixed precision
    fp16_backend="amp"      # Use PyTorch AMP
)

# Add gradient norm monitoring
class GradientMonitorCallback(TrainerCallback):
    def on_step_end(self, args, state, control, model=None, **kwargs):
        if state.global_step % 100 == 0:
            for name, param in model.named_parameters():
                if param.grad is not None:
                    grad_norm = param.grad.norm().item()
                    if grad_norm > 100:
                        print(f"High gradient norm in {name}: {grad_norm}")

3. Slow Training Speed

# Problem: Training too slow
# Solution 1: Optimize DataLoader
from torch.utils.data import DataLoader

train_dataloader = DataLoader(
    dataset["train"],
    batch_size=training_args.per_device_train_batch_size,
    num_workers=4,           # Parallel data loading
    pin_memory=True,        # Faster data transfer to GPU
    prefetch_factor=2       # Prefetch next batches
)

# Solution 2: Profile your training
from torch.profiler import profile, record_function, ProfilerActivity

with profile(activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA]) as prof:
    trainer.train()
print(prof.key_averages().table(sort_by="cuda_time_total"))

4. Training Instability

# Problem: Unstable loss or metrics
# Solution 1: Learning Rate Finder
from transformers import get_scheduler

def find_learning_rate(trainer, min_lr=1e-7, max_lr=1):
    lr_finder = trainer.lr_find(
        min_lr=min_lr,
        max_lr=max_lr,
        num_training_steps=100,
        early_stopping=True
    )
    return lr_finder.suggestion()

# Solution 2: Batch Size Finder
def find_batch_size(trainer):
    batch_finder = trainer.find_batch_size(
        starting_batch_size=4,
        max_batch_size=128,
        growth_rate=2
    )
    return batch_finder.suggestion()

Adjusting Parameters Based on Resources

For different hardware configurations:

  1. High-end GPU (A100, 80GB):
training_args = TrainingArguments(
    per_device_train_batch_size=16,
    gradient_accumulation_steps=1,
    fp16=True
)
  1. Mid-range GPU (RTX 3090, 24GB):
training_args = TrainingArguments(
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    fp16=True,
    gradient_checkpointing=True
)
  1. Limited GPU (RTX 3060, 12GB):
training_args = TrainingArguments(
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,
    fp16=True,
    gradient_checkpointing=True,
    max_steps=1000  # Limit training steps if needed
)
  1. Fine-tuning Process:
from transformers import Trainer, TrainingArguments
from datasets import load_dataset

# Load your dataset
dataset = load_dataset('json', data_files={'train': 'train.json'})

# Initialize trainer
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=dataset["train"],
    data_collator=data_collator,
)

# Start training
trainer.train()

Best Practices for Training

  1. Data Preparation:
  • Ensure high-quality, clean training data
  • Implement proper data validation
  • Use appropriate tokenization
  • Balance your dataset
  1. Training Optimization:
  • Start with small learning rates
  • Use gradient accumulation for larger effective batch sizes
  • Implement early stopping
  • Monitor training metrics carefully
  1. Resource Management:
  • Use mixed precision training (fp16)
  • Implement gradient checkpointing
  • Use efficient attention mechanisms
  • Properly handle memory management

Common Challenges and Solutions

  1. Memory Issues:
  • Use gradient checkpointing
  • Implement efficient attention mechanisms
  • Utilize model parallelism when necessary
  1. Training Stability:
  • Implement learning rate warmup
  • Use gradient clipping
  • Monitor loss curves carefully
  1. Overfitting:
  • Implement proper validation
  • Use early stopping
  • Apply dropout and regularization

Conclusion

Running and training LLMs locally has become more accessible than ever. While LM Studio provides an excellent platform for inference, training your own models requires more technical expertise and computational resources. Start with smaller models and gradually work your way up as you gain experience and understanding of the process.

Remember to always monitor system resources, back up your models, and follow best practices for both inference and training. The field of AI is rapidly evolving, so stay updated with the latest developments and techniques.

Essential Tools and Documentation

Learning Resources

Community and Support

Model Resources

Hardware Optimization Guides

Happy modeling! 🙂