DDColor: Photo-Realistic Image Colorization

repository·master·Indexed 23 days ago

https://github.com/piddnad/ddcolor

Official PyTorch implementation of the ICCV 2023 paper 'DDColor: Towards Photo-Realistic Image Colorization via Dual Decoders'. DDColor provides high-quality colorization for black and white photos and anime landscapes. It supports inference via local scripts, ModelScope pipelines, and Hugging Face Hub, with options for ONNX export and runtime acceleration using TensorRT, CUDA, or CPU providers. The model zoo includes variants such as ddcolor_modelscope, ddcolor_artistic, ddcolor_paper, and ddcolor_paper_tiny.

Tokens
3.4K
Snippets
9
Records
11
Agent score
81%

What's inside DDColor

  1. Install DDColor via Conda

    master

    To set up DDColor in a clean environment, it is recommended to use Conda. This process involves creating a Python 3.9 environment, installing PyTorch with CUDA support, and then installing the project requirements.

    Requirements:

    • Python >= 3.7
    • PyTorch >= 1.7

    For Training: If you intend to train the model, you must also install additional dependencies and basicsr using the training requirements file and running the setup script in develop mode.

    conda create -n ddcolor python=3.9
    conda activate ddcolor
    pip install torch==2.2.0 torchvision==0.17.0 --index-url https://download.pytorch.org/whl/cu118
    
    pip install -r requirements.txt
    
    # For training, install the following additional dependencies and basicsr
    pip install -r requirements.train.txt
    python3 setup.py develop
  2. Run inference using a local script

    master

    You can perform image colorization locally without requiring basicsr.

    1. Download the pretrained model using ModelScope's snapshot download.
    2. Run the inference script by pointing to the downloaded model path and your input image directory.
    from modelscope.hub.snapshot_download import snapshot_download
    
    model_dir = snapshot_download('damo/cv_ddcolor_image-colorization', cache_dir='./modelscope')
    print('model assets saved to %s' % model_dir)
    python scripts/infer.py --model_path ./modelscope/damo/cv_ddcolor_image-colorization/pytorch_model.pt --input ./assets/test_images
  3. Train DDColor from scratch

    master

    Training DDColor involves several steps:

    1. Dataset Preparation: Use python scripts/get_meta_file.py to generate a dataset list file from ImageNet or a custom dataset.
    2. Pretrained Weights: Download weights for ConvNeXt and InceptionV3 and place them in the pretrain folder.
    3. Configuration: Edit options/train/train_ddcolor.yml to specify the meta_info_file and other training hyperparameters.
    4. Execution: Run the training script via sh scripts/train.sh.
  4. Export DDColor model to ONNX

    master

    DDColor supports ONNX export. You must first install onnx, onnxruntime, and onnxsim.

    Usage: Run the export_onnx.py script providing the path to your pretrained .pth model and the desired output path for the .onnx file.

    pip install onnx==1.16.1 onnxruntime==1.19.2 onnxsim==0.4.36
    
    python scripts/export_onnx.py --model_path pretrain/ddcolor_paper_tiny.pth --export_path weights/ddcolor-tiny.onnx
  5. Run DDColor inference using ONNX Runtime

    master

    You can perform image colorization using an exported ONNX model via onnxruntime. The process involves loading the model, preparing a grayscale RGB input tensor, running the session, and post-processing the output AB channels back into a full RGB image.

    Workflow Summary:

    1. Load Model: Initialize an ort.InferenceSession with your .onnx model path.
    2. Prepare Input: Convert the input image to grayscale by transforming it to Lab color space, extracting the L channel, and converting it back to an RGB-format tensor (where A and B channels are zero).
    3. Inference: Pass the tensor to ort_session.run().
    4. Post-process: Interpolate the output AB channels to the original image size, concatenate them with the original L channel, and convert the resulting Lab image back to RGB.
    import numpy as np
    import onnxruntime as ort
    import cv2
    import torch
    import torch.nn.functional as F
    
    # 1. Load Model
    model_path = 'weights/ddcolor-tiny-op12.onnx'
    ort_session = ort.InferenceSession(model_path, providers=['CPUExecutionProvider'])
    
    # 2. Prepare Input
    img = cv2.imread('input.jpg', cv2.IMREAD_COLOR)
    height, width = img.shape[:2]
    img_float = (img / 255.0).astype(np.float32)
    orig_l = cv2.cvtColor(img_float, cv2.COLOR_BGR2Lab)[:, :, :1]
    
    input_size = 512
    img_resize = cv2.resize(img_float, (input_size, input_size))
    img_l = cv2.cvtColor(img_resize, cv2.COLOR_BGR2Lab)[:, :, :1]
    img_gray_lab = np.concatenate((img_l, np.zeros_like(img_l), np.zeros_like(img_l)), axis=-1)
    img_gray_rgb = cv2.cvtColor(img_gray_lab, cv2.COLOR_LAB2RGB)
    img_gray_rgb = img_gray_rgb.transpose((2, 0, 1)).astype(np.float32)
    img_gray_rgb = np.expand_dims(img_gray_rgb, axis=0)
    
    inputs = {ort_session.get_inputs()[0].name: img_gray_rgb}
    
    # 3. Inference
    output_ab = torch.from_numpy(ort_session.run(None, inputs)[0])
    
    # 4. Post-process
    output_ab_resize = F.interpolate(output_ab, size=(height, width))[0].float().numpy().transpose(1, 2, 0)
    output_lab = np.concatenate((orig_l, output_ab_resize), axis=-1)
    output_rgb = cv2.cvtColor(output_lab, cv2.COLOR_LAB2RGB)
    output_img = (output_rgb * 255.0).round().astype(np.uint8)
  6. Run inference using ModelScope Pipeline

    master

    You can use the ModelScope pipeline API to perform colorization. This method automatically handles model downloading and inference. Ensure you have modelscope and opencv-python installed.

    import cv2
    from modelscope.outputs import OutputKeys
    from modelscope.pipelines import pipeline
    from modelscope.utils.constant import Tasks
    
    img_colorization = pipeline(Tasks.image_colorization, model='damo/cv_ddcolor_image-colorization')
    result = img_colorization('https://modelscope.oss-cn-beijing.aliyuncs.com/test/images/audrey_hepburn.jpg')
    cv2.imwrite('result.png', result[OutputKeys.OUTPUT_IMG])
  7. Load DDColor via Hugging Face Hub

    master

    To use DDColor with the Hugging Face ecosystem, you can wrap the DDColor class with PyTorchModelHubMixin. This allows you to load different pretrained model variants directly using .from_pretrained().

    Available model names:

    • piddnad/ddcolor_paper_tiny
    • piddnad/ddcolor_paper
    • piddnad/ddcolor_modelscope
    • piddnad/ddcolor_artistic
    from huggingface_hub import PyTorchModelHubMixin
    from ddcolor import DDColor
    
    class DDColorHF(DDColor, PyTorchModelHubMixin):
        def __init__(self, config=None, **kwargs):
            if isinstance(config, dict):
                kwargs = {**config, **kwargs}
            super().__init__(**kwargs)
    
    ddcolor_paper_tiny = DDColorHF.from_pretrained("piddnad/ddcolor_paper_tiny")
    ddcolor_paper      = DDColorHF.from_pretrained("piddnad/ddcolor_paper")
    ddcolor_modelscope = DDColorHF.from_pretrained("piddnad/ddcolor_modelscope")
    ddcolor_artistic   = DDColorHF.from_pretrained("piddnad/ddcolor_artistic")
  8. Select a DDColor model from the Model Zoo

    master

    DDColor provides several pre-trained models optimized for different use cases. When performing inference, choose a model_name based on your requirements:

    • ddcolor_modelscope (Default): Best for general use and testing images outside of ImageNet. It uses a specific data cleaning scheme to achieve high qualitative results with minimal FID degradation.
    • ddcolor_artistic: Best for high-quality artistic results. It was trained on an extended dataset of artistic images and does not use colorfulness loss, which may reduce color artifacts.
    • ddcolor_paper: Use this only if you need to reproduce specific images from the original DDColor paper (DDColor-L trained on ImageNet).
    • ddcolor_paper_tiny: The most lightweight version (DDColor-T trained on ImageNet).
  9. Benchmark DDColor ONNX Inference

    master

    To measure the performance of your DDColor ONNX deployment, run the inference session multiple times (e.g., 100 iterations) and calculate the average time per batch, per image, and the resulting FPS (Frames Per Second).

    import time
    import tqdm
    import numpy as np
    
    # Run the model 100 times to get an average time
    times = []
    for i in tqdm.tqdm(range(100)):
        start = time.time()
        outputs = ort_session.run(None, inputs)
        times.append(time.time() - start)
    
    print(f"Average time per batch: {np.mean(times):.4f} seconds")
    print(f"Average time per image: {np.mean(times)/batch_size:.4f} seconds")
    print(f"Average FPS per image: {batch_size/np.mean(times):.4f}")
  10. Configure ONNX Runtime Execution Providers

    master

    To optimize performance, you can specify different execution providers in ort.InferenceSession.

    • TensorrtExecutionProvider: The fastest option for NVIDIA GPUs. Supports FP16 and engine caching.
    • CUDAExecutionProvider: Standard GPU acceleration. Note that it may be slower than PyTorch for certain large matrix multiplications used in DDColor.
    • CPUExecutionProvider: Fallback for CPU-only environments.

    When using TensorRT, you can configure workspace size, FP16, and engine cache paths to speed up subsequent runs.

    providers = [
        ('TensorrtExecutionProvider', {
            'device_id': 0,
            'trt_max_workspace_size': 4 * 1024 * 1024 * 1024,
            'trt_fp16_enable': True,
            'trt_engine_cache_enable': True,
            'trt_engine_cache_path': './trt_engine_cache',
            'trt_engine_cache_prefix': 'model',
            'trt_dump_subgraphs': False,
            'trt_timing_cache_enable': True,
            'trt_timing_cache_path': './trt_engine_cache',
        }),
        ('CUDAExecutionProvider', {
            'device_id': 0,
            'gpu_mem_limit': 4 * 1024 * 1024 * 1024,
        }),
        ('CPUExecutionProvider', {})
    ]
    
    ort_session = ort.InferenceSession(model_path, providers=providers)