Skip to page content
SAVRN
Search Plan a project

Open-weight model · Image to image

photo-to-sketch-unet

by WILLIAMS OPOKU ANTWI Willie999/photo-to-sketch-unet

photo-to-sketch-unet is an open-weight model for image to image from WILLIAMS OPOKU ANTWI, released under MIT License. It has 31M parameters. At 16-bit it needs about 0.1 GB of GPU memory, which fits on 1x MI300X from $1.85 an hour, at the lowest prices in the SAVRN Index.

This model is a custom PyTorch U-Net architecture (SketchUNet) trained to convert RGB photos into target outline sketches using the rhfeiyang/photo-sketch-pair-500 dataset.

Parameters31M
Context—
Weights248.5 MB
Licensemit
AccessOpen weights
Monthly Downloads—

Runs On

What it takes to serve photo-to-sketch-unet (31M parameters): the memory its weights need at each precision, and the cheapest way to rent enough data-center GPUs to hold them.

PrecisionWeightsMemory neededCheapest setupPer hourAlso fits
16-bit 0.1 GB 0.1 GB 1x MI300X (192 GB)
Vultr
$1.85 1x H100 $1.99 · 1x MI325X $2.00
8-bit 0.0 GB 0.0 GB 1x MI300X (192 GB)
Vultr
$1.85 1x H100 $1.99 · 1x MI325X $2.00
4-bit 0.0 GB 0.0 GB 1x MI300X (192 GB)
Vultr
$1.85 1x H100 $1.99 · 1x MI325X $2.00

Memory is the weights at that precision plus 20% for the runtime and a short context; a long context needs more. Prices are the lowest on-demand hourly rates in the SAVRN Index, read Oct 18, 2026.

photo-to-sketch-unet on every accelerator the SAVRN Index prices, at every precision

Model Card

By WILLIAMS OPOKU ANTWI, published under mit, revision 1592fd90dc16.

This model is a custom PyTorch U-Net architecture (SketchUNet) trained to convert RGB photos into target outline sketches using the rhfeiyang/photo-sketch-pair-500 dataset. - Combined Sketch Loss (L1 + Sobel Edge Loss): 0.14555 - Mean Absolute Error (L1 / MAE): 0.04962 This model converts an RGB image into a grayscale sketch using a PyTorch U-Net architecture. The model checkpoint is available as: Once the model architecture is defined, inference can be reduced to

Read WILLIAMS OPOKU ANTWI's full model card

Photo-to-Sketch U-Net Model

This model is a custom PyTorch U-Net architecture (SketchUNet) trained to convert RGB photos into target outline sketches using the rhfeiyang/photo-sketch-pair-500 dataset.

Final Evaluation Metrics on Validation Set

  • Combined Sketch Loss (L1 + Sobel Edge Loss): 0.14555
  • Mean Absolute Error (L1 / MAE): 0.04962
  • Mean Squared Error (MSE): 0.00653
  • Structural Similarity Index (SSIM): 0.8804
  • Peak Signal-to-Noise Ratio (PSNR): 22.68 dB

Hyperparameters

  • Epochs: 50
  • Batch Size: 8
  • Optimizer: AdamW (Learning Rate: 2e-4, Weight Decay: 1e-4)
  • Scheduler: CosineAnnealingLR (T_max: 50)

Usage

This model converts an RGB image into a grayscale sketch using a PyTorch U-Net architecture.

Requirements

pip install torch torchvision pillow matplotlib

Load the model

The model checkpoint is available as:

best_sketch_unet.pt

First, define the model architecture:

import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms
from PIL import Image
import matplotlib.pyplot as plt


class DoubleConv(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()

        self.block = nn.Sequential(
            nn.Conv2d(in_channels, out_channels, 3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True),

            nn.Conv2d(out_channels, out_channels, 3, padding=1),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(inplace=True)
        )

    def forward(self, x):
        return self.block(x)


class Down(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()

        self.block = nn.Sequential(
            nn.MaxPool2d(2),
            DoubleConv(in_channels, out_channels)
        )

    def forward(self, x):
        return self.block(x)


class Up(nn.Module):
    def __init__(self, in_channels, out_channels):
        super().__init__()

        self.up = nn.ConvTranspose2d(
            in_channels,
            in_channels // 2,
            kernel_size=2,
            stride=2
        )

        self.conv = DoubleConv(
            in_channels,
            out_channels
        )

    def forward(self, x1, x2):
        x1 = self.up(x1)

        diff_y = x2.size(2) - x1.size(2)
        diff_x = x2.size(3) - x1.size(3)

        x1 = F.pad(
            x1,
            [
                diff_x // 2,
                diff_x - diff_x // 2,
                diff_y // 2,
                diff_y - diff_y // 2
            ]
        )

        x = torch.cat([x2, x1], dim=1)

        return self.conv(x)


class SketchUNet(nn.Module):
    def __init__(self):
        super().__init__()

        self.input = DoubleConv(3, 64)

        self.down1 = Down(64, 128)
        self.down2 = Down(128, 256)
        self.down3 = Down(256, 512)

        self.bottleneck = Down(512, 1024)

        self.up1 = Up(1024, 512)
        self.up2 = Up(512, 256)
        self.up3 = Up(256, 128)
        self.up4 = Up(128, 64)

        self.output = nn.Conv2d(64, 1, kernel_size=1)

    def forward(self, x):
        x1 = self.input(x)

        x2 = self.down1(x1)
        x3 = self.down2(x2)
        x4 = self.down3(x3)

        x5 = self.bottleneck(x4)

        x = self.up1(x5, x4)
        x = self.up2(x, x3)
        x = self.up3(x, x2)
        x = self.up4(x, x1)

        return torch.sigmoid(self.output(x))

Download and load the checkpoint

from huggingface_hub import hf_hub_download

checkpoint = hf_hub_download(
    repo_id="Willie999/photo-to-sketch-unet",
    filename="best_sketch_unet.pt"
)

device = torch.device(
    "cuda" if torch.cuda.is_available() else "cpu"
)

model = SketchUNet().to(device)

model.load_state_dict(
    torch.load(
        checkpoint,
        map_location=device
    )
)

model.eval()

Generate a sketch

image = Image.open(
    "your_image.jpg"
).convert("RGB")

transform = transforms.Compose([
    transforms.Resize((256, 256)),
    transforms.ToTensor()
])

input_tensor = transform(image)
input_tensor = input_tensor.unsqueeze(0).to(device)

with torch.no_grad():
    sketch = model(input_tensor)

sketch = sketch[0, 0].cpu()

Display the result

plt.figure(figsize=(8, 8))

plt.imshow(
    sketch,
    cmap="gray"
)

plt.axis("off")
plt.show()

Save the generated sketch

output = (
    sketch.clamp(0, 1) * 255
).byte()

output_image = Image.fromarray(
    output.numpy()
)

output_image.save(
    "generated_sketch.png"
)

Complete minimal example

Once the model architecture is defined, inference can be reduced to:

from huggingface_hub import hf_hub_download
from PIL import Image
from torchvision import transforms
import torch

device = torch.device(
    "cuda" if torch.cuda.is_available() else "cpu"
)

checkpoint = hf_hub_download(
    repo_id="Willie999/photo-to-sketch-unet",
    filename="best_sketch_unet.pt"
)

model = SketchUNet().to(device)

model.load_state_dict(
    torch.load(
        checkpoint,
        map_location=device
    )
)

model.eval()

image = Image.open(
    "your_image.jpg"
).convert("RGB")

transform = transforms.Compose([
    transforms.Resize((256, 256)),
    transforms.ToTensor()
])

x = transform(image).unsqueeze(0).to(device)

with torch.no_grad():
    sketch = model(x)

sketch = (
    sketch[0, 0]
    .cpu()
    .clamp(0, 1)
    .mul(255)
    .byte()
)

Image.fromarray(
    sketch.numpy()
).save("generated_sketch.png")

Input / Output

Input: RGB image

Output: Grayscale sketch

Input resolution: 256 × 256

Task: Image-to-image translation

Architecture: U-Net

Framework: PyTorch

The model is trained on paired photo/sketch examples from the rhfeiyang/photo-sketch-pair-500 dataset. It is intended as an experimental general image-to-sketch model and may perform differently depending on the subject, composition, and visual style of the input image.

Configuration

Architecture
SketchUNetModel
Model type
sketch_unet

Identity and Version

Repository
Willie999/photo-to-sketch-unet
Publisher
WILLIAMS OPOKU ANTWI
Task
Image to image
Modality
Image
Library
Not stated by the source
Parameters
31M parameters
Languages
en
Revision
1592fd90dc161425053e0d16edcf668f1a64f03e
First published
2026-10-03
Last updated
2026-10-03

Files and Weights

9 files, 248.5 MB in total. The weights are 2 files totalling 248.5 MB in pt, safetensors.

Weights2 files · 248.5 MB
Configuration3 files · 3.2 KB
Documentation1 file · 6.3 KB
Other2 files · 6.2 KB
Repository1 file · 1.5 KB
Every file
FileTypeSizeSHA-256
best_sketch_unet.ptWeights124.3 MB 4506868702bf
model.safetensorsWeights124.2 MB 04775602a941
config.jsonConfiguration322 B —
configuration_sketch_unet.pyConfiguration297 B —
modeling_sketch_unet.pyConfiguration2.6 KB —
README.mdDocumentation6.3 KB —
__pycache__/configuration_sketch_unet.cpython-313.pycOther827 B —
__pycache__/modeling_sketch_unet.cpython-313.pycOther5.4 KB —
.gitattributesRepository1.5 KB —

License and Download

License
mit
Access
Open weights, no gate
Download size
248.5 MB
Download from WILLIAMS OPOKU ANTWI

Released by WILLIAMS OPOKU ANTWI through its official repository on Hugging Face. Read the license.

Memory Requirements

PrecisionWeights in memory
As published248.5 MB
16-bit0.1 GB
8-bit0.0 GB
4-bit0.0 GB

Weights only, from the published parameter count; the key-value cache and runtime add to this.

Questions About photo-to-sketch-unet

How much GPU memory does photo-to-sketch-unet need?

About 0.1 GB at 16-bit and 0 GB at 4-bit: the weights (31M parameters) plus a working margin. A long context needs more.

What is the cheapest GPU to run photo-to-sketch-unet on?

At 16-bit, 1x MI300X from $1.85 an hour; at 4-bit, 1x MI300X from $1.85 an hour, at the lowest on-demand prices the SAVRN Index lists.

Can I use photo-to-sketch-unet commercially?

Yes. photo-to-sketch-unet is released under MIT License. The MIT License is a short permissive license. It permits commercial use, modification and redistribution, provided the copyright notice and permission notice are included.

Similar Models

Model · Image to image

mini-unet-colorizer

Joe Bloggs

Status: evaluated app-testing candidate. Some broad color patches and incorrect object hues remain. Predicted colors are not evidence of original historical colors. This checkpoint has 3,968,892 learned parameters and 236 fixed color bins. It starts from the audited bin-mapping repair of main commit 6c47ea40724d8fcd67d4f36ce837dc1cb5b1b2a8 and changes all 65 learned parameter tensors. The color vocabulary is unchanged. The selected weights are update 748 of a completed 1,122-update BF16 L4 run using a 17,325-photo mixed training pool (11,943 Imagenette plus 5,382 COCO), batch 32, initial learning rate 1e-5, weighted classification loss and frozen BatchNorm running statistics. Selection…

Open weights apache-2.0 4M parameters

Model · Image to image

MadStickArt

Danger Room

MadStickArt is a trained, 61,296-parameter neural raster decoder for stick-figure storyboard scenes. It reconstructs 956 × 400 grayscale frames from four explicit layout masks: actors, setting, props, and motion. Its output contract is 2.39:1. Try MadStickArt online → — the browser trial is deployed separately. Its deployed model/version and renderer are recorded in the Space's model-provenance.json. The renderer included with this release supports 186 settings and 320 props; the deployed trial has its own model and renderer pins and is updated through a separate reviewed stage. Browser suggestions use transparent rules, while Strands decisions run in the downloadable Python pipeline. The…

Open weights apache-2.0 61,296 parameters pytorch

Model · Image to image

MadStickArt-v0.8.0

Danger Room

MadStickArt is a trained, 61,296-parameter neural raster decoder for stick-figure storyboard scenes. It reconstructs 956 × 400 grayscale frames from four explicit layout masks: actors, setting, props, and motion. Its output contract is 2.39:1. Try MadStickArt online → — the browser trial is deployed separately. Its deployed model/version and renderer are recorded in the Space's model-provenance.json. The renderer included with this release supports 186 settings and 320 props; the deployed trial has its own model and renderer pins and is updated through a separate reviewed stage. Browser suggestions use transparent rules, while Strands decisions run in the downloadable Python pipeline. The…

Open weights apache-2.0 61,296 parameters pytorch

Model · Image to image

MadStickArt-v0.1.0

Danger Room

Try MadStickArt online → — generate a storyboard in your browser before downloading. Adjust composition and camera controls, then export clean or annotated PNGs and scene JSON. The playground runs the released neural decoder locally and uses optional rule-based scene suggestions; Strands Decider is available in the downloadable Python pipeline. MadStickArt is a small, trained 12,192-parameter image model for clean stick-figure storyboard scenes at 956 × 400 pixels, exactly 2.39:1. This first public release is danger-room/MadStickArt-v0.1.0, licensed under Apache 2.0. Pin revision v0.1.0 for reproducible downloads. The model is a custom PyTorch layout-conditioned neural raster decoder. A…

Open weights apache-2.0 12,192 parameters pytorch

Model · Image to image

FLUX.2-klein-4B-GGUF

Unsloth AI

This is a GGUF quantized version of FLUX.2-klein-4B. unsloth/FLUX.2-klein-4B-GGUF uses Unsloth Dynamic 2.0 methodology for SOTA performance. - Important layers are upcasted to higher precision. - Uses tooling from ComfyUI-GGUF by city96. The FLUX.2 [klein] model family are our fastest image models to date. FLUX.2 [klein] unifies generation and editing in a single compact architecture, delivering state-of-the-art quality with end-to-end inference in as low as under a second. Built for applications that require real-time image generation without sacrificing quality, and runs on consumer hardware, with as little as 13GB VRAM. FLUX.2 [klein] 4B is a 4 billion parameter rectified flow…

Open weights apache-2.0 ggml