initial setup: ComfyUI + kohya_ss scripts, LoRA config, workflows
This commit is contained in:
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# models - too large for git
|
||||||
|
models/
|
||||||
|
*.safetensors
|
||||||
|
*.ckpt
|
||||||
|
*.pt
|
||||||
|
*.pth
|
||||||
|
*.bin
|
||||||
|
|
||||||
|
# generated outputs
|
||||||
|
output/
|
||||||
|
outputs/
|
||||||
|
|
||||||
|
# venvs / installs
|
||||||
|
comfyui/venv/
|
||||||
|
comfyui/__pycache__/
|
||||||
|
kohya_ss/venv/
|
||||||
|
kohya_ss/__pycache__/
|
||||||
|
kohya_ss/logs/
|
||||||
|
|
||||||
|
# training data (images)
|
||||||
|
training_data/
|
||||||
|
|
||||||
|
# ComfyUI user data / cache
|
||||||
|
comfyui/user/
|
||||||
|
comfyui/temp/
|
||||||
|
comfyui/custom_nodes/**/node_modules/
|
||||||
|
|
||||||
|
# misc
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
72
README.md
Normal file
72
README.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# animepics
|
||||||
|
|
||||||
|
Anime image generation + LoRA training setup.
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- **ComfyUI** — image generation UI
|
||||||
|
- **NoobAI-XL** — base anime model (SDXL-based, SFW+NSFW)
|
||||||
|
- **kohya_ss** — LoRA training
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- Python 3.10+ installed and in PATH
|
||||||
|
- Git installed
|
||||||
|
- NVIDIA GPU with CUDA (4070 recommended)
|
||||||
|
- ~20GB free disk space for models
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Run once to install everything:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\setup.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
1. Clone ComfyUI and install dependencies
|
||||||
|
2. Clone kohya_ss and install dependencies
|
||||||
|
3. Install ComfyUI custom nodes (AnimateDiff, ControlNet, etc.)
|
||||||
|
4. Download the NoobAI-XL base model + VAE
|
||||||
|
|
||||||
|
## Launch
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Start image generation UI (opens browser at localhost:8188)
|
||||||
|
.\launch_comfyui.ps1
|
||||||
|
|
||||||
|
# Start LoRA training UI (opens browser at localhost:7860)
|
||||||
|
.\launch_kohya.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
## LoRA Training
|
||||||
|
|
||||||
|
1. Put your training images in `training_data/<your_lora_name>/img/10_<trigger_word>/`
|
||||||
|
2. Copy `training/example_lora_config.toml` and edit it
|
||||||
|
3. Launch kohya and use the GUI, or run `.\train_lora.ps1 <config_file>`
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
animepics/
|
||||||
|
├── comfyui/ # ComfyUI install (gitignored venv)
|
||||||
|
├── kohya_ss/ # kohya_ss install (gitignored venv)
|
||||||
|
├── models/ # shared model storage (gitignored)
|
||||||
|
│ ├── checkpoints/ # base models (.safetensors)
|
||||||
|
│ ├── loras/ # trained LoRAs
|
||||||
|
│ ├── vae/ # VAE models
|
||||||
|
│ ├── embeddings/ # textual inversions
|
||||||
|
│ └── controlnet/ # ControlNet models
|
||||||
|
├── training_data/ # LoRA training images (gitignored)
|
||||||
|
├── output/ # generated images (gitignored)
|
||||||
|
├── training/ # LoRA training configs
|
||||||
|
└── workflows/ # ComfyUI workflow JSON files
|
||||||
|
```
|
||||||
|
|
||||||
|
## Model Downloads
|
||||||
|
|
||||||
|
Base model (NoobAI-XL Vpred):
|
||||||
|
- https://civitai.com/models/833294
|
||||||
|
|
||||||
|
Good NSFW VAE:
|
||||||
|
- Already baked into NoobAI, but sdxl_vae.safetensors from stabilityai works too
|
||||||
11
config/extra_model_paths.yaml
Normal file
11
config/extra_model_paths.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# ComfyUI extra model paths — points to shared models/ directory
|
||||||
|
# so both ComfyUI and kohya_ss use the same model storage
|
||||||
|
|
||||||
|
animepics:
|
||||||
|
base_path: E:/animepics/models
|
||||||
|
checkpoints: checkpoints
|
||||||
|
loras: loras
|
||||||
|
vae: vae
|
||||||
|
embeddings: embeddings
|
||||||
|
controlnet: controlnet
|
||||||
|
upscale_models: upscale_models
|
||||||
12
launch_comfyui.ps1
Normal file
12
launch_comfyui.ps1
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
# launch_comfyui.ps1 — start ComfyUI
|
||||||
|
|
||||||
|
$root = $PSScriptRoot
|
||||||
|
Set-Location "$root/comfyui"
|
||||||
|
|
||||||
|
.\venv\Scripts\Activate.ps1
|
||||||
|
python main.py `
|
||||||
|
--listen 127.0.0.1 `
|
||||||
|
--port 8188 `
|
||||||
|
--extra-model-paths-config "$root/comfyui/extra_model_paths.yaml" `
|
||||||
|
--preview-method auto
|
||||||
8
launch_kohya.ps1
Normal file
8
launch_kohya.ps1
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
# launch_kohya.ps1 — start kohya_ss GUI
|
||||||
|
|
||||||
|
$root = $PSScriptRoot
|
||||||
|
Set-Location "$root/kohya_ss"
|
||||||
|
|
||||||
|
.\venv\Scripts\Activate.ps1
|
||||||
|
python kohya_gui.py --listen 127.0.0.1 --server_port 7860
|
||||||
88
setup.ps1
Normal file
88
setup.ps1
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
# setup.ps1 — one-time install of ComfyUI + kohya_ss
|
||||||
|
|
||||||
|
$root = $PSScriptRoot
|
||||||
|
Set-Location $root
|
||||||
|
|
||||||
|
Write-Host "==> setting up animepics environment" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# create model dirs
|
||||||
|
$model_dirs = @(
|
||||||
|
"models/checkpoints",
|
||||||
|
"models/loras",
|
||||||
|
"models/vae",
|
||||||
|
"models/embeddings",
|
||||||
|
"models/controlnet",
|
||||||
|
"models/upscale_models",
|
||||||
|
"training_data",
|
||||||
|
"output"
|
||||||
|
)
|
||||||
|
foreach ($dir in $model_dirs) {
|
||||||
|
New-Item -ItemType Directory -Force -Path "$root/$dir" | Out-Null
|
||||||
|
}
|
||||||
|
Write-Host " created model directories" -ForegroundColor Green
|
||||||
|
|
||||||
|
# --- ComfyUI ---
|
||||||
|
Write-Host "`n==> installing ComfyUI" -ForegroundColor Cyan
|
||||||
|
if (-not (Test-Path "$root/comfyui")) {
|
||||||
|
git clone https://github.com/comfyanonymous/ComfyUI.git "$root/comfyui"
|
||||||
|
} else {
|
||||||
|
Write-Host " comfyui already cloned, pulling latest" -ForegroundColor Yellow
|
||||||
|
git -C "$root/comfyui" pull
|
||||||
|
}
|
||||||
|
|
||||||
|
Push-Location "$root/comfyui"
|
||||||
|
python -m venv venv
|
||||||
|
.\venv\Scripts\Activate.ps1
|
||||||
|
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
pip install -r requirements.txt
|
||||||
|
deactivate
|
||||||
|
Pop-Location
|
||||||
|
Write-Host " ComfyUI installed" -ForegroundColor Green
|
||||||
|
|
||||||
|
# ComfyUI custom nodes
|
||||||
|
Write-Host "`n==> installing ComfyUI custom nodes" -ForegroundColor Cyan
|
||||||
|
$custom_nodes = @(
|
||||||
|
@{ name="ComfyUI-Manager"; url="https://github.com/ltdrdata/ComfyUI-Manager.git" },
|
||||||
|
@{ name="ComfyUI_IPAdapter_plus"; url="https://github.com/cubiq/ComfyUI_IPAdapter_plus.git" },
|
||||||
|
@{ name="ComfyUI-Advanced-ControlNet"; url="https://github.com/Kosinkadink/ComfyUI-Advanced-ControlNet.git" },
|
||||||
|
@{ name="was-node-suite-comfyui"; url="https://github.com/WASasquatch/was-node-suite-comfyui.git" }
|
||||||
|
)
|
||||||
|
New-Item -ItemType Directory -Force -Path "$root/comfyui/custom_nodes" | Out-Null
|
||||||
|
foreach ($node in $custom_nodes) {
|
||||||
|
$node_path = "$root/comfyui/custom_nodes/$($node.name)"
|
||||||
|
if (-not (Test-Path $node_path)) {
|
||||||
|
git clone $node.url $node_path
|
||||||
|
Write-Host " cloned $($node.name)" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
git -C $node_path pull
|
||||||
|
Write-Host " updated $($node.name)" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# copy extra_model_paths config so ComfyUI finds our shared models dir
|
||||||
|
Copy-Item -Force "$root/config/extra_model_paths.yaml" "$root/comfyui/extra_model_paths.yaml"
|
||||||
|
Write-Host " copied extra_model_paths.yaml" -ForegroundColor Green
|
||||||
|
|
||||||
|
# --- kohya_ss ---
|
||||||
|
Write-Host "`n==> installing kohya_ss" -ForegroundColor Cyan
|
||||||
|
if (-not (Test-Path "$root/kohya_ss")) {
|
||||||
|
git clone https://github.com/bmaltais/kohya_ss.git "$root/kohya_ss"
|
||||||
|
} else {
|
||||||
|
Write-Host " kohya_ss already cloned, pulling latest" -ForegroundColor Yellow
|
||||||
|
git -C "$root/kohya_ss" pull
|
||||||
|
}
|
||||||
|
|
||||||
|
Push-Location "$root/kohya_ss"
|
||||||
|
python -m venv venv
|
||||||
|
.\venv\Scripts\Activate.ps1
|
||||||
|
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
|
||||||
|
pip install -r requirements.txt
|
||||||
|
deactivate
|
||||||
|
Pop-Location
|
||||||
|
Write-Host " kohya_ss installed" -ForegroundColor Green
|
||||||
|
|
||||||
|
Write-Host "`n==> setup complete!" -ForegroundColor Cyan
|
||||||
|
Write-Host " next: download your base model into models/checkpoints/" -ForegroundColor White
|
||||||
|
Write-Host " recommended: NoobAI-XL from https://civitai.com/models/833294" -ForegroundColor White
|
||||||
|
Write-Host "`n then run: .\launch_comfyui.ps1" -ForegroundColor White
|
||||||
23
train_lora.ps1
Normal file
23
train_lora.ps1
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
# train_lora.ps1 — run LoRA training from a config file
|
||||||
|
# usage: .\train_lora.ps1 training/my_lora.toml
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$config_file
|
||||||
|
)
|
||||||
|
|
||||||
|
$root = $PSScriptRoot
|
||||||
|
|
||||||
|
if (-not (Test-Path "$root/$config_file")) {
|
||||||
|
Write-Host "config file not found: $config_file" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Set-Location "$root/kohya_ss"
|
||||||
|
.\venv\Scripts\Activate.ps1
|
||||||
|
|
||||||
|
accelerate launch `
|
||||||
|
--num_cpu_threads_per_process 2 `
|
||||||
|
train_network.py `
|
||||||
|
--config_file "$root/$config_file"
|
||||||
54
training/example_lora_config.toml
Normal file
54
training/example_lora_config.toml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# example LoRA training config for kohya_ss (SDXL)
|
||||||
|
# copy this, rename it, and edit the paths/settings for your lora
|
||||||
|
# then train with: .\train_lora.ps1 training/my_lora.toml
|
||||||
|
|
||||||
|
[model_arguments]
|
||||||
|
pretrained_model_name_or_path = "E:/animepics/models/checkpoints/noobai-xl.safetensors"
|
||||||
|
# set to true for vpred models (NoobAI-XL uses vpred)
|
||||||
|
v_parameterization = true
|
||||||
|
zero_terminal_snr = true
|
||||||
|
|
||||||
|
[saving_arguments]
|
||||||
|
save_every_n_epochs = 1
|
||||||
|
save_model_as = "safetensors"
|
||||||
|
output_dir = "E:/animepics/models/loras"
|
||||||
|
output_name = "my_lora_v1"
|
||||||
|
|
||||||
|
[dataset_arguments]
|
||||||
|
# dataset dir structure: training_data/<lora_name>/img/<repeats>_<trigger>/
|
||||||
|
train_data_dir = "E:/animepics/training_data/my_lora/img"
|
||||||
|
resolution = "1024,1024"
|
||||||
|
enable_bucket = true
|
||||||
|
min_bucket_reso = 512
|
||||||
|
max_bucket_reso = 2048
|
||||||
|
bucket_reso_steps = 64
|
||||||
|
caption_extension = ".txt"
|
||||||
|
shuffle_caption = true
|
||||||
|
keep_tokens = 1
|
||||||
|
|
||||||
|
[training_arguments]
|
||||||
|
output_dir = "E:/animepics/models/loras"
|
||||||
|
logging_dir = "E:/animepics/kohya_ss/logs"
|
||||||
|
max_train_epochs = 10
|
||||||
|
train_batch_size = 1
|
||||||
|
gradient_accumulation_steps = 1
|
||||||
|
gradient_checkpointing = true
|
||||||
|
mixed_precision = "bf16"
|
||||||
|
save_precision = "bf16"
|
||||||
|
seed = 42
|
||||||
|
max_token_length = 225
|
||||||
|
xformers = true
|
||||||
|
# learning rates — good defaults for NoobAI-XL
|
||||||
|
learning_rate = 0.0001
|
||||||
|
unet_lr = 0.0001
|
||||||
|
text_encoder_lr = 0.00005
|
||||||
|
lr_scheduler = "cosine_with_restarts"
|
||||||
|
lr_warmup_steps = 100
|
||||||
|
optimizer_type = "AdamW8bit"
|
||||||
|
|
||||||
|
[network_arguments]
|
||||||
|
network_module = "networks.lora"
|
||||||
|
network_dim = 32 # rank — higher = more capacity, 16-64 is typical
|
||||||
|
network_alpha = 16 # usually half of dim
|
||||||
|
# optional: train only specific layers
|
||||||
|
# network_args = ["conv_dim=16", "conv_alpha=8"]
|
||||||
120
workflows/anime_txt2img.json
Normal file
120
workflows/anime_txt2img.json
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
{
|
||||||
|
"last_node_id": 9,
|
||||||
|
"last_link_id": 9,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"type": "CheckpointLoaderSimple",
|
||||||
|
"pos": [26, 474],
|
||||||
|
"size": [315, 98],
|
||||||
|
"flags": {},
|
||||||
|
"order": 0,
|
||||||
|
"mode": 0,
|
||||||
|
"outputs": [
|
||||||
|
{"name": "MODEL", "type": "MODEL", "links": [1], "slot_index": 0},
|
||||||
|
{"name": "CLIP", "type": "CLIP", "links": [3, 5], "slot_index": 1},
|
||||||
|
{"name": "VAE", "type": "VAE", "links": [8], "slot_index": 2}
|
||||||
|
],
|
||||||
|
"properties": {"Node name for S&R": "CheckpointLoaderSimple"},
|
||||||
|
"widgets_values": ["noobai-xl.safetensors"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"type": "CLIPTextEncode",
|
||||||
|
"pos": [415, 186],
|
||||||
|
"size": [422, 164],
|
||||||
|
"flags": {},
|
||||||
|
"order": 2,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [{"name": "clip", "type": "CLIP", "link": 3}],
|
||||||
|
"outputs": [{"name": "CONDITIONING", "type": "CONDITIONING", "links": [4], "slot_index": 0}],
|
||||||
|
"properties": {"Node name for S&R": "CLIPTextEncode"},
|
||||||
|
"widgets_values": ["1girl, anime, masterpiece, best quality, highly detailed, beautiful face, solo"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"type": "CLIPTextEncode",
|
||||||
|
"pos": [415, 400],
|
||||||
|
"size": [422, 164],
|
||||||
|
"flags": {},
|
||||||
|
"order": 3,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [{"name": "clip", "type": "CLIP", "link": 5}],
|
||||||
|
"outputs": [{"name": "CONDITIONING", "type": "CONDITIONING", "links": [6], "slot_index": 0}],
|
||||||
|
"properties": {"Node name for S&R": "CLIPTextEncode"},
|
||||||
|
"widgets_values": ["worst quality, low quality, bad anatomy, extra limbs, poorly drawn face, ugly, watermark, text"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"type": "EmptyLatentImage",
|
||||||
|
"pos": [473, 609],
|
||||||
|
"size": [315, 106],
|
||||||
|
"flags": {},
|
||||||
|
"order": 1,
|
||||||
|
"mode": 0,
|
||||||
|
"outputs": [{"name": "LATENT", "type": "LATENT", "links": [2], "slot_index": 0}],
|
||||||
|
"properties": {"Node name for S&R": "EmptyLatentImage"},
|
||||||
|
"widgets_values": [832, 1216, 1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"type": "KSampler",
|
||||||
|
"pos": [863, 186],
|
||||||
|
"size": [315, 474],
|
||||||
|
"flags": {},
|
||||||
|
"order": 4,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{"name": "model", "type": "MODEL", "link": 1},
|
||||||
|
{"name": "positive", "type": "CONDITIONING", "link": 4},
|
||||||
|
{"name": "negative", "type": "CONDITIONING", "link": 6},
|
||||||
|
{"name": "latent_image", "type": "LATENT", "link": 2}
|
||||||
|
],
|
||||||
|
"outputs": [{"name": "LATENT", "type": "LATENT", "links": [7], "slot_index": 0}],
|
||||||
|
"properties": {"Node name for S&R": "KSampler"},
|
||||||
|
"widgets_values": [42, "fixed", 28, 7, "dpmpp_2m", "karras", 1]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"type": "VAEDecode",
|
||||||
|
"pos": [1209, 186],
|
||||||
|
"size": [210, 46],
|
||||||
|
"flags": {},
|
||||||
|
"order": 5,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{"name": "samples", "type": "LATENT", "link": 7},
|
||||||
|
{"name": "vae", "type": "VAE", "link": 8}
|
||||||
|
],
|
||||||
|
"outputs": [{"name": "IMAGE", "type": "IMAGE", "links": [9], "slot_index": 0}],
|
||||||
|
"properties": {"Node name for S&R": "VAEDecode"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"type": "SaveImage",
|
||||||
|
"pos": [1451, 186],
|
||||||
|
"size": [210, 58],
|
||||||
|
"flags": {},
|
||||||
|
"order": 6,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [{"name": "images", "type": "IMAGE", "link": 9}],
|
||||||
|
"properties": {"Node name for S&R": "SaveImage"},
|
||||||
|
"widgets_values": ["anime"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"links": [
|
||||||
|
[1, 4, 0, 3, 0, "MODEL"],
|
||||||
|
[2, 5, 0, 3, 3, "LATENT"],
|
||||||
|
[3, 4, 1, 6, 0, "CLIP"],
|
||||||
|
[4, 6, 0, 3, 1, "CONDITIONING"],
|
||||||
|
[5, 4, 1, 7, 0, "CLIP"],
|
||||||
|
[6, 7, 0, 3, 2, "CONDITIONING"],
|
||||||
|
[7, 3, 0, 8, 0, "LATENT"],
|
||||||
|
[8, 4, 2, 8, 1, "VAE"],
|
||||||
|
[9, 8, 0, 9, 0, "IMAGE"]
|
||||||
|
],
|
||||||
|
"groups": [],
|
||||||
|
"config": {},
|
||||||
|
"extra": {"ds": {"scale": 0.8, "offset": [0, 0]}},
|
||||||
|
"version": 0.4
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user