AI & Tech

Self-Host AI Image Generation: Jalankan Stable Diffusion di VPS Sendiri

Self-Host AI Image Generation: Jalankan Stable Diffusion di VPS Sendiri

Bulan Maret lalu, client gw minta bikin 50 gambar produk untuk katalog e-commerce mereka. Budget: Rp500.000. Gw hitung: kalau pake DALL·E 3, $0.04 per image × 50 = $2 — cheap. Tapi masalahnya: mereka butuh produk spesifik dengan angle dan background yang konsisten. DALL·E gak bisa di-fine-tune semudah itu. Midjourney bisa, tapi $30/bulan + limited API. Solusi? Self-host Stable Diffusion di VPS.

Gw bisa duga lo mikir: "Stable Diffusion butuh GPU. VPS gak punya GPU." Betul — VPS biasa gak punya NVIDIA GPU. Tapi ada trik: CPU inference dengan optimasi, atau GPU cloud spot instances. Dan untuk kasus client gw, ternyata CPU inference di VPS 4GB cukup kok — cuma lebih lambat. 1 gambar butuh 3-5 menit vs 5 detik di GPU. Tapi untuk batch processing semalaman? Selesai semua.

Artikel ini bakal jelasin 3 cara self-host image generation AI: (1) CPU-only di VPS murah, (2) GPU murah via runpod.io, (3) hybrid approach dengan API fallback. Kalau lo tertarik dengan self-host AI secara umum, cek dulu panduan self-host LLM dengan Ollama — banyak konsep yang overlap.

Cara 1: CPU-Only Stable Diffusion di VPS 4GB

Ini opsi paling murah dan paling gampang. Lo gak butuh GPU sama sekali — cuma butuh kesabaran karena prosesnya lambat. Cocok untuk batch processing yang gak perlu real-time.

# Setup environment
apt update && apt install -y python3 python3-pip wget unzip

# Install diffusers (HuggingFace library)
pip install diffusers transformers accelerate pillow

# Download model (Stable Diffusion 1.5 — paling ringan untuk CPU)
python3 -c "
from diffusers import StableDiffusionPipeline
import torch

# SD 1.5 — 1.2GB download, cocok untuk CPU
pipe = StableDiffusionPipeline.from_pretrained(
    'runwayml/stable-diffusion-v1-5',
    torch_dtype=torch.float32
)
pipe.save_pretrained('/models/sd15')
print('Model downloaded!')
"

Kenapa SD 1.5 dan bukan SDXL atau SD3? Karena model-model baru itu butuh lebih banyak VRAM/RAM. SD 1.5 cuma butuh ~3GB RAM untuk ukuran 512×512. SDXL butuh 7-8GB — gak muat di VPS 4GB. Tapi untuk 90% use case, SD 1.5 udah cukup. Kualitasnya oke untuk social media, blog, dan materi marketing.

Inference Script

# generate.py
from diffusers import StableDiffusionPipeline
from PIL import Image
import time, os

MODEL_PATH = '/models/sd15'
OUTPUT_DIR = '/output'

pipe = StableDiffusionPipeline.from_pretrained(MODEL_PATH)
pipe = pipe.to('cpu')
# Enable memory optimizations
pipe.enable_attention_slicing()

def generate_image(prompt, filename, negative_prompt='', steps=25):
    start = time.time()
    image = pipe(
        prompt,
        negative_prompt=negative_prompt or 'blurry, low quality, deformed',
        num_inference_steps=steps,
        guidance_scale=7.5,
        width=512,
        height=512
    ).images[0]
    
    elapsed = time.time() - start
    os.makedirs(OUTPUT_DIR, exist_ok=True)
    image.save(f'{OUTPUT_DIR}/{filename}.png')
    return elapsed

# Test
t = generate_image(
    'a modern tech office with servers, digital art style',
    'test-office',
    steps=20
)
print(f'Done in {t:.1f}s')
# Output: ~210 detik di VPS 4 vCPU

Hasil benchmark di VPS 4 vCPU (tanpa GPU): 210 detik per gambar ukuran 512×512 — sekitar 3.5 menit. Untuk 50 gambar: 175 menit (~3 jam). Jalanin semalem, besok pagi udah selesai semua. Gak usah dipantau — cukup cron job yang jalan jam 2 pagi.

Optimasi Lebih Lanjut

  • Reduce steps: 15 steps instead of 25 dapat mengurangi waktu 40% dengan kualitas yang hampir sama. Bedanya subtle — mostly cuma di detail halus.
  • Use Tiny AutoEncoder: Model yang lebih kecil untuk upscale. Bisa kurangi waktu 20% tanpa quality loss yang signifikan.
  • Batch processing: Generate beberapa gambar sekaligus dalam satu pipeline call. Di CPU, ini lebih efisien karena model cuma di-load sekali.
  • Use ONNX Runtime: Optimasi CPU-specific via Microsoft's ONNX Runtime. Bisa speed up 30-50%. Tapi setup-nya lebih kompleks.

Cara 2: GPU Murah via RunPod / Vast.ai

Kalau lo butuh gambar cepet (kurang dari 1 menit per gambar), lo butuh GPU. Tapi beli GPU sendiri? Mahal. RTX 4090 $1,600+. Solusi: cloud GPU dengan spot instances.

Gw pake RunPod untuk client project. Harganya $0.35/jam untuk RTX 3090 (24GB VRAM). Untuk generate 50 gambar: ~8 menit total = $0.05. Lebih murah dari DALL·E 3 ($2 untuk 50 gambar). Dan lo kontrol penuh — fine-tune model, LoRA, ControlNet, semuanya bisa.

# RunPod template: stable-diffusion-webui (AUTOMATIC1111)
# Setup: pilih template, deploy, SSH ke pod

# Fine-tune dengan LoRA
# LoRA = Low Rank Adaptation — training kecil tanpa full fine-tune
# Contoh: LoRA untuk produk spesifik client gw
# Bikin LoRA dari 20 foto produk

python3 train_lora.py   --model sd_xl_base_1.0.safetensors   --data /images/products/   --output /models/lora/product-lora.safetensors   --rank 16   --batch_size 1   --epochs 20

# Generate dengan LoRA
python3 generate_with_lora.py   --model sd_xl_base_1.0.safetensors   --lora /models/lora/product-lora.safetensors   --prompt 'product photo, studio lighting, white background, <lora:product-lora:0.8>'   --output /output/

Yang gw pelajari dari training LoRA: 20 foto cukup untuk hasil yang konsisten. Asal foto-fotonya punya angle dan lighting yang seragam — produk dari front, side, 45-degree, dengan background putih. Kalau foto produk lo berantakan (selfie dengan background kamar), hasil LoRA-nya juga bakal jelek. GIGO — garbage in, garbage out — berlaku juga buat AI.

Hasil buat client gw: 50 gambar katalog selesai dalam 15 menit dengan konsistensi 90% ke produk asli. Client puas, bayar tepat waktu. Total biaya GPU: $0.42. Bandingkan dengan bayar fotografer produk: Rp500.000-1.000.000 per sesi.

Cara 3: Hybrid — CPU + API Fallback

Arsitektur hybrid: CPU inference untuk batch jobs yang gak urgent, API fallback (Replicate/Together.ai) untuk request yang butuh cepat.

# hybrid-generator.py — pilih mode berdasarkan urgency
import os, requests, time, json

MODEL_SD15_PATH = '/models/sd15'
API_KEY = os.getenv('REPLICATE_API_KEY')
API_MODEL = 'stability-ai/stable-diffusion-3.5'

def generate_cpu(prompt):
    """CPU inference — slow tapi gratis"""
    from diffusers import StableDiffusionPipeline
    pipe = StableDiffusionPipeline.from_pretrained(MODEL_SD15_PATH).to('cpu')
    image = pipe(prompt, num_inference_steps=25).images[0]
    return image

def generate_api(prompt):
    """API — cepat tapi bayar per request"""
    resp = requests.post(
        'https://api.replicate.com/v1/models/' + API_MODEL + '/predictions',
        headers={'Authorization': f'Bearer {API_KEY}'},
        json={'input': {'prompt': prompt, 'width': 1024, 'height': 1024}}
    )
    return resp.json()

def smart_generate(prompt, mode='auto'):
    if mode == 'auto':
        # API untuk jam sibuk, CPU untuk malam
        hour = time.localtime().tm_hour
        if 8 <= hour <= 22:
            return generate_api(prompt)
        else:
            return generate_cpu(prompt)
    elif mode == 'fast':
        return generate_api(prompt)
    else:
        return generate_cpu(prompt)

Di VPS gw, cron job jalan jam 2 pagi untuk batch generate semua gambar yang di-queue seharian. Kalau ada request urgent di jam kerja, fallback ke API — bayar $0.002 per gambar pakai SD 3.5 di Replicate. Total biaya API per bulan: $2-5. Jauh lebih murah dari langganan Midjourney $30/bulan.

Optimasi Output: Resolusi dan Format

Buat toolkuy.com, gw butuh gambar 1200×630px (OG image standard) dalam format WebP. Masalahnya, Stable Diffusion generate di 512×512 atau 1024×1024 — aspect ratio-nya beda. Solusi: outpainting + upscale.

from diffusers import StableDiffusionPipeline
from PIL import Image, ImageFilter

def generate_og_image(prompt, output_path):
    # Generate base image di 512×512
    pipe = StableDiffusionPipeline.from_pretrained(MODEL_SD15_PATH)
    pipe = pipe.to('cpu')
    base = pipe(prompt, num_inference_steps=25).images[0]
    
    # Upscale ke 1200×630 dengan resize + sharpen
    # Gak perlu model upscale terpisah — cukup Lanczos + Unsharp Mask
    img_1200 = base.resize((1200, 630), Image.LANCZOS)
    img_sharp = img_1200.filter(
        ImageFilter.UnsharpMask(radius=1.5, percent=80, threshold=3)
    )
    
    # Convert ke WebP
    img_sharp.save(output_path, 'WEBP', quality=85, method=6)
    return output_path

# Test
generate_og_image(
    'abstract technology network, blue and neon colors, clean design',
    '/images/ai-generated-tech.webp'
)

Hasil: gambar 1200×630 WebP dengan ukuran 80-120KB. Quality 85% dengan method=6 (slowest encoding, best compression). Bandingkan dengan JPEG 200KB di quality yang sama. Buat SEO, ukuran file kecil itu penting — PageSpeed Insights kasih penalty buat gambar >100KB yang gak di-lazy load. Baca juga strategi optimasi biaya infrastruktur untuk lebih hemat di VPS.

Perbandingan Biaya

MethodCost/ImageTime/ImageKualitasSetup Complexity
CPU (VPS 4GB)Gratis (VPS existing)3.5 menitSD 1.5 — 512×512Rendah
GPU Cloud (RunPod)$0.0008 (3090)8 detikSDXL — 1024×1024Medium
Hybrid CPU+API$0.002 (API fallback)~10 detikSD 3.5 — 1024×1024Medium
DALL·E 3 API$0.04~5 detikBest qualityRendah
Midjourney (manual)$30/bln (~$0.01/img)~30 detikBest qualitySangat Rendah

Untuk developer Indonesia yang punya VPS dan butuh gambar untuk konten/blog: CPU inference di VPS sendiri adalah paling ekonomis. Lo cuma bayar listrik VPS yang udah jalan. 50 gambar semalem selesai. Kualitas SD 1.5 emang gak sebagus Midjourney, tapi untuk blog, social media, dan materi marketing — lebih dari cukup. Apalagi kalau lo tambahin post-processing (upscale + filter) kayak yang gw contohin di atas.

Kalau lo serius mau self-host AI tools, jangan lupa baca container security hardening dan Docker BuildKit optimization — karena semua AI tools ini jalan di Docker container yang perlu di-secure dan di-optimize dengan benar.

💬 Komentar (0)

Belum ada komentar. Jadilah yang pertama! 💬

Komentar akan muncul setelah moderasi.