# Civitai LoRA Training Guide

This guide covers training custom LoRAs using the Civitai training API for both
image and video generation models.

## Overview

The Civitai training integration supports:

- **Image LoRAs**: Character, style, and object training on SD1.5/SDXL/Flux
- **Video LoRAs**: Motion training on Wan and Hunyuan video models
- **Training Presets**: Pre-configured hyperparameters for common use cases
- **Progress Monitoring**: Real-time loss tracking and sample generation
- **Cost Estimation**: Accurate training cost predictions

## Quick Start

### Basic Training Example

```typescript
import {
  LoraTrainingProvider,
  createLoraTrainingProvider,
} from '@oshun/civitai-training';

const training = createLoraTrainingProvider(process.env.CIVITAI_API_KEY);

// Train a character LoRA
const job = await training.trainCharacterLoRA(
  'my-character', // name
  images, // dataset images
  'mycharacter', // trigger word
  { epochs: 15 } // optional customization
);

console.log('Training started:', job.id);
console.log('Estimated cost:', job.cost, 'Buzz');
```

## Dataset Preparation

### Image Dataset

```typescript
import type { DatasetImage, DatasetConfig } from '@oshun/civitai-training';

// Prepare images
const images: DatasetImage[] = [
  {
    image: 'https://example.com/image1.jpg', // URL or base64
    caption: 'mycharacter, woman, portrait, looking at camera',
    repeats: 5, // higher repeats for important images
  },
  {
    image: 'https://example.com/image2.jpg',
    caption: 'mycharacter, woman, full body, standing',
    repeats: 3,
  },
  // Add 10-50 images for best results
];

// Dataset configuration
const dataset: DatasetConfig = {
  name: 'my-character-dataset',
  images,
  triggerWord: 'mycharacter',
  classWord: 'woman', // for regularization
  captionMode: 'caption', // 'tag', 'caption', or 'auto'
  autoCaption: false, // use AI captioning
  resolution: 1024, // training resolution
  bucketResolutionSteps: 64, // aspect ratio bucketing
  enableCropping: true,
  flipProbability: 0.5, // horizontal flip augmentation
};
```

### Video Dataset

```typescript
import type { DatasetVideo } from '@oshun/civitai-training';

const videos: DatasetVideo[] = [
  {
    video: 'https://example.com/clip1.mp4',
    caption: 'smooth camera pan, cinematic motion',
    startTime: 0,
    endTime: 4, // seconds
  },
  {
    video: 'https://example.com/clip2.mp4',
    caption: 'zooming in, dynamic movement',
  },
  // Add 10+ clips for motion LoRAs
];
```

### Dataset Guidelines

| Training Type  | Min Images | Recommended | Notes                            |
| -------------- | ---------- | ----------- | -------------------------------- |
| Character      | 10         | 20-50       | Varied poses, angles, lighting   |
| Style          | 20         | 50-100      | Consistent style across subjects |
| Object         | 15         | 30-60       | Multiple angles and contexts     |
| Motion (Video) | 10 clips   | 30+ clips   | 2-5 second clips                 |

### Caption Modes

| Mode      | Description                   | Best For                    |
| --------- | ----------------------------- | --------------------------- |
| `tag`     | Comma-separated tags          | Anime, stylized content     |
| `caption` | Natural language descriptions | Realistic, detailed content |
| `auto`    | AI-generated captions         | Large datasets              |

## Training Presets

### Available Presets

| Preset              | Base Model    | Use Case                  | Rank | Epochs |
| ------------------- | ------------- | ------------------------- | ---- | ------ |
| `character-sdxl`    | SDXL          | Character/person training | 128  | 15     |
| `style-sdxl`        | SDXL          | Art style training        | 32   | 10     |
| `object-sdxl`       | SDXL          | Object/product training   | 64   | 20     |
| `character-flux`    | Flux Dev      | Character on Flux         | 64   | 10     |
| `style-flux`        | Flux Dev      | Style on Flux             | 16   | 8      |
| `motion-wan`        | Wan 2.1       | Video motion training     | 64   | 20     |
| `character-hunyuan` | Hunyuan Video | Character for video       | 64   | 15     |
| `fast-test`         | SDXL          | Quick testing             | 8    | 3      |

### Using Presets

```typescript
// Train with preset
const job = await training.startTrainingWithPreset(
  'character-sdxl', // preset name
  dataset, // dataset config
  'my-character-lora', // training name
  {
    // Optional: override specific settings
    epochs: 20,
    learningRate: {
      unetLR: 0.00005,
    },
  }
);
```

### Preset Configurations

```typescript
// Character SDXL preset configuration
const characterSDXL = {
  network: { rank: 128, alpha: 64, dropout: 0.05 },
  learningRate: {
    unetLR: 0.00007,
    textEncoderLR: 0.000035,
    scheduler: 'cosine_with_warmup',
    warmup: 0.1,
  },
  optimizer: 'AdamW8bit',
  batchSize: 2,
  epochs: 15,
  mixedPrecision: 'bf16',
  gradientCheckpointing: true,
  xformers: true,
};

// Style SDXL preset configuration
const styleSDXL = {
  network: { rank: 32, alpha: 16, dropout: 0.1 },
  learningRate: {
    unetLR: 0.0001,
    textEncoderLR: 0.00005,
    scheduler: 'cosine',
    warmup: 0.05,
  },
  optimizer: 'AdamW8bit',
  batchSize: 4,
  epochs: 10,
  mixedPrecision: 'bf16',
};
```

## Custom Training Configuration

### Full Configuration Example

```typescript
import type {
  TrainingConfig,
  TrainingHyperparams,
} from '@oshun/civitai-training';

const hyperparams: TrainingHyperparams = {
  network: {
    rank: 64, // Network dimension (4-256)
    alpha: 32, // Scaling factor (usually rank or rank/2)
    dropout: 0.05, // Dropout for regularization
    convRank: 32, // For LoCon (optional)
    convAlpha: 16, // For LoCon (optional)
  },
  learningRate: {
    unetLR: 0.0001, // U-Net learning rate
    textEncoderLR: 0.00005, // Text encoder learning rate
    scheduler: 'cosine_with_warmup',
    warmup: 0.1, // 10% warmup steps
    minLR: 0.00001, // Minimum LR at end
    numCycles: 1, // For cosine_with_restarts
  },
  optimizer: 'AdamW8bit', // Memory-efficient optimizer
  batchSize: 2,
  epochs: 15,
  maxSteps: undefined, // Override epochs with fixed steps
  gradientAccumulationSteps: 1,
  mixedPrecision: 'bf16', // bf16 for newer GPUs, fp16 otherwise
  gradientCheckpointing: true,
  xformers: true,
  seed: 42,
  cacheLatents: true,
  noiseOffset: 0.1, // For better blacks/whites
  priorPreservationWeight: 1.0, // For DreamBooth
};

const config: TrainingConfig = {
  name: 'my-custom-lora',
  baseModel: 'sdxl',
  trainingType: 'lora',
  dataset,
  hyperparams,
  outputPath: '/trained-loras/',
  callbackUrl: 'https://api.myapp.com/webhooks/training',
  saveEveryNEpochs: 5,
  sampleEveryNEpochs: 5,
  samplePrompts: [
    'mycharacter, portrait, high quality',
    'mycharacter, full body, standing',
  ],
};

const job = await training.startTraining(config);
```

### Network Parameters

| Parameter  | Range  | Description                                |
| ---------- | ------ | ------------------------------------------ |
| `rank`     | 4-256  | Network dimension (higher = more capacity) |
| `alpha`    | 1-rank | Scaling factor (common: rank/2 or rank)    |
| `dropout`  | 0-0.3  | Regularization (0.05-0.1 recommended)      |
| `convRank` | 4-64   | Convolutional rank for LoCon               |

### Learning Rate Guidelines

| Base Model | U-Net LR    | Text Encoder LR |
| ---------- | ----------- | --------------- |
| SD 1.5     | 1e-4 - 5e-4 | 5e-5 - 2e-4     |
| SDXL       | 5e-5 - 1e-4 | 2.5e-5 - 5e-5   |
| Flux       | 5e-5 - 2e-4 | 2.5e-5 - 1e-4   |

### Schedulers

| Scheduler              | Description          | Use Case           |
| ---------------------- | -------------------- | ------------------ |
| `constant`             | Fixed learning rate  | Short training     |
| `constant_with_warmup` | Warmup then constant | General purpose    |
| `linear`               | Linear decay         | Long training      |
| `cosine`               | Cosine decay         | Most recommended   |
| `cosine_with_restarts` | Periodic restarts    | Very long training |
| `polynomial`           | Polynomial decay     | Fine-tuning        |

### Optimizers

| Optimizer    | VRAM   | Speed  | Description                    |
| ------------ | ------ | ------ | ------------------------------ |
| `AdamW`      | High   | Fast   | Standard optimizer             |
| `AdamW8bit`  | Low    | Fast   | Memory-efficient (recommended) |
| `SGD`        | Low    | Medium | Simple, stable                 |
| `Lion`       | Medium | Fast   | Newer, efficient               |
| `Prodigy`    | Medium | Fast   | Adaptive LR                    |
| `DAdaptAdam` | Medium | Medium | Self-tuning LR                 |

## Supported Base Models

### Image Models

| Model ID       | Name          | Min VRAM | Notes                     |
| -------------- | ------------- | -------- | ------------------------- |
| `sd15`         | SD 1.5        | 6GB      | Fast, broad compatibility |
| `sd21`         | SD 2.1        | 8GB      | Improved quality          |
| `sdxl`         | SDXL 1.0      | 12GB     | High quality, recommended |
| `flux-dev`     | Flux Dev      | 24GB     | Best quality              |
| `flux-schnell` | Flux Schnell  | 20GB     | Faster Flux               |
| `sd35-medium`  | SD 3.5 Medium | 16GB     | Latest SD                 |
| `sd35-large`   | SD 3.5 Large  | 24GB     | Best SD 3.5               |
| `pony-v6`      | Pony V6       | 12GB     | Anime/stylized            |

### Video Models

| Model ID        | Name          | Min VRAM | Notes           |
| --------------- | ------------- | -------- | --------------- |
| `hunyuan-video` | Hunyuan Video | 24GB     | Character LoRAs |
| `wan-2.1`       | Wan 2.1       | 24GB     | Motion LoRAs    |
| `wan-2.2`       | Wan 2.2       | 24GB     | Improved Wan    |

## Training Helpers

### Character LoRA

```typescript
// Quick character training
const job = await training.trainCharacterLoRA('john-doe', images, 'johndoe', {
  epochs: 20,
  network: { rank: 128 },
});
```

### Style LoRA

```typescript
// Style training with lower rank
const job = await training.trainStyleLoRA(
  'watercolor-style',
  images,
  'watercolor',
  {
    network: { rank: 32 },
  }
);
```

### Motion LoRA

```typescript
// Video motion training
const job = await training.trainMotionLoRA(
  'smooth-pan',
  videoClips,
  'smoothpan',
  {
    epochs: 25,
  }
);
```

### Hunyuan Character LoRA

```typescript
// Character for Hunyuan video
const job = await training.trainHunyuanLoRA(
  'my-character-hunyuan',
  images,
  'mychar'
);
```

## Progress Monitoring

### Job Status

```typescript
// Get job by ID
const job = training.getJob(jobId);

console.log('Status:', job.status);
console.log('Progress:', job.progress?.progress * 100, '%');
console.log('Current epoch:', job.progress?.currentEpoch);
console.log('Current step:', job.progress?.currentStep);
console.log('Loss:', job.progress?.loss.currentLoss);
```

### Job Status Flow

```
queued → preparing → training → completed
                             → failed
                             → cancelled
```

### Event Handling

```typescript
// Listen for training events
training.on('training:started', ({ job }) => {
  console.log('Training started:', job.id);
});

training.on('training:progress', ({ jobId, progress }) => {
  console.log(`${jobId}: ${progress.progress * 100}%`);
  console.log(`Loss: ${progress.loss.currentLoss}`);
  console.log(`ETA: ${progress.estimatedTimeRemaining}s`);
});

training.on('training:sample', ({ jobId, sample }) => {
  console.log(`Sample generated at step ${sample.step}:`);
  console.log(`URL: ${sample.imageUrl}`);
});

training.on('training:checkpoint', ({ jobId, checkpoint }) => {
  console.log(`Checkpoint saved at epoch ${checkpoint.epoch}`);
  console.log(`Download: ${checkpoint.downloadUrl}`);
});

training.on('training:completed', ({ job }) => {
  console.log('Training completed!');
  console.log('LoRA URL:', job.loraUrl);
});

training.on('training:failed', ({ jobId, error }) => {
  console.error('Training failed:', error);
});
```

### Loss Metrics

```typescript
const progress = job.progress;

// Loss tracking
console.log('Current loss:', progress.loss.currentLoss);
console.log('Average loss:', progress.loss.averageLoss);
console.log('Best loss:', progress.loss.bestLoss);
console.log('Best loss step:', progress.loss.bestLossStep);

// Loss history
for (const point of progress.loss.lossHistory) {
  console.log(`Step ${point.step}: ${point.loss}`);
}
```

### Waiting for Completion

```typescript
// Wait with default timeout
const completedJob = await training.waitForTraining(jobId);
console.log('LoRA URL:', completedJob.loraUrl);

// Wait with custom timeout (2 hours)
const job = await training.waitForTraining(jobId, 7200000);
```

## Cost Estimation

### Calculating Training Cost

```typescript
import {
  estimateTrainingCost,
  calculateTotalSteps,
} from '@oshun/civitai-training';

// Calculate total steps
const totalSteps = calculateTotalSteps(
  50, // imageCount
  5, // repeats per image
  2, // batchSize
  15 // epochs
);
// (50 * 5) / 2 * 15 = 1875 steps

// Estimate cost
const cost = estimateTrainingCost('sdxl', totalSteps);
console.log('Estimated cost:', cost, 'Buzz');
```

### Cost Per 1000 Steps

| Base Model    | Cost/1000 Steps |
| ------------- | --------------- |
| SD 1.5        | 50 Buzz         |
| SD 2.1        | 50 Buzz         |
| SDXL          | 100 Buzz        |
| Flux Dev      | 200 Buzz        |
| Flux Schnell  | 150 Buzz        |
| SD 3.5 Medium | 120 Buzz        |
| SD 3.5 Large  | 180 Buzz        |
| Pony V6       | 100 Buzz        |
| Hunyuan Video | 300 Buzz        |
| Wan 2.1       | 300 Buzz        |
| Wan 2.2       | 350 Buzz        |

### Time Estimation

```typescript
import { estimateTrainingTime } from '@oshun/civitai-training';

// Estimate time (default 0.5 steps/second)
const timeSeconds = estimateTrainingTime(1875);
console.log('Estimated time:', timeSeconds / 60, 'minutes');

// With custom speed
const timeWithSpeed = estimateTrainingTime(1875, 0.8);
```

## Validation

### Dataset Validation

```typescript
import { validateDataset } from '@oshun/civitai-training';

const validation = validateDataset(dataset);

if (!validation.valid) {
  console.error('Dataset errors:', validation.errors);
  // [
  //   'Minimum 4 images required for effective training',
  //   'Dataset must contain at least one image or video'
  // ]
}
```

### Hyperparameter Validation

```typescript
import { validateHyperparams } from '@oshun/civitai-training';

const validation = validateHyperparams(hyperparams);

if (!validation.valid) {
  console.error('Errors:', validation.errors);
}

if (validation.warnings.length > 0) {
  console.warn('Warnings:', validation.warnings);
  // [
  //   'Alpha is typically equal to or less than rank',
  //   'More than 50 epochs may lead to overfitting'
  // ]
}
```

### Optimal Learning Rate

```typescript
import { calculateOptimalLR } from '@oshun/civitai-training';

// Calculate optimal LR based on rank
const optimalLR = calculateOptimalLR(
  128, // rank
  0.0001 // base LR
);
// Scales based on rank^-0.84
```

## Job Management

### Cancelling Training

```typescript
await training.cancelJob(jobId);
```

### Getting All Jobs

```typescript
const allJobs = training.getAllJobs();

for (const job of allJobs) {
  console.log(`${job.id}: ${job.status}`);
  if (job.progress) {
    console.log(`  Progress: ${job.progress.progress * 100}%`);
  }
}
```

### Downloading Results

```typescript
// Download completed LoRA
const { url, filename } = await training.downloadLoRA(jobId);
console.log('Download URL:', url);
console.log('Filename:', filename);
```

## Best Practices

### Dataset Preparation

1. **Quality over quantity**: 20 high-quality images > 100 poor ones
2. **Variety**: Include different poses, angles, lighting, backgrounds
3. **Consistency**: Keep style/subject consistent within dataset
4. **Resolution**: Use images at or above training resolution
5. **Captions**: Detailed captions improve quality significantly

### Hyperparameter Tuning

1. **Start with presets**: Use presets as baseline
2. **Rank selection**: Higher rank = more capacity but risk of overfitting
3. **Learning rate**: Start low, increase if underfitting
4. **Epochs**: Monitor loss, stop if it increases
5. **Batch size**: Larger batches = more stable, but need more VRAM

### Training Monitoring

1. **Watch the loss curve**: Should decrease smoothly
2. **Check samples**: Visual quality is ultimate measure
3. **Look for overfitting**: Loss goes up or samples look identical
4. **Save checkpoints**: Keep intermediate checkpoints

### Common Issues

| Issue                   | Symptoms                                  | Solution                        |
| ----------------------- | ----------------------------------------- | ------------------------------- |
| Overfitting             | Samples look identical to training images | Reduce epochs, increase dropout |
| Underfitting            | LoRA has no effect                        | Increase rank, LR, or epochs    |
| Catastrophic forgetting | Model loses base capabilities             | Lower LR, use regularization    |
| Mode collapse           | Limited variety in outputs                | Increase dataset variety        |

## Error Handling

### Error Codes

| Code                | Description               |
| ------------------- | ------------------------- |
| `AUTH_FAILED`       | Invalid API key           |
| `INSUFFICIENT_BUZZ` | Not enough Buzz balance   |
| `INVALID_DATASET`   | Dataset validation failed |
| `INVALID_CONFIG`    | Invalid hyperparameters   |
| `TRAINING_FAILED`   | Training failed on server |
| `JOB_NOT_FOUND`     | Job doesn't exist         |
| `TIMEOUT`           | Training timed out        |

### Error Handling Example

```typescript
import { LoraTrainingError } from '@oshun/civitai-training';

try {
  const job = await training.startTraining(config);
  const completed = await training.waitForTraining(job.id);
} catch (error) {
  if (error instanceof LoraTrainingError) {
    switch (error.code) {
      case 'INSUFFICIENT_BUZZ':
        console.error('Not enough Buzz. Please top up.');
        break;
      case 'INVALID_DATASET':
        console.error('Dataset issues:', error.details);
        break;
      case 'TRAINING_FAILED':
        console.error('Training failed:', error.message);
        break;
      default:
        console.error('Error:', error.message);
    }
  }
}
```

## Lifecycle Management

### Shutdown

```typescript
// Graceful shutdown - cancels running jobs
await training.shutdown();
```

## TypeScript Types

```typescript
import type {
  // Dataset Types
  DatasetImage,
  DatasetVideo,
  DatasetConfig,
  DatasetStats,

  // Training Configuration
  TrainingConfig,
  TrainingHyperparams,
  NetworkParams,
  LearningRateParams,

  // Base Models
  TrainingBaseModel,
  TrainingType,
  TrainingPreset,

  // Job Types
  TrainingJob,
  TrainingStatus,
  TrainingProgress,

  // Progress Types
  LossMetrics,
  TrainingSample,
  TrainingCheckpoint,

  // Configuration
  LoraTrainingConfig,
  OptimizerType,
  LRScheduler,
  CaptionMode,
} from '@oshun/civitai-training';
```

## Related Documentation

- [API Documentation](./api.md) - Generation API reference
- [Model Management](./model-management.md) - Model discovery and downloads
- [Best Practices](./best-practices.md) - Optimization and cost management
