styler00dollar / VSGAN-tensorrt-docker

Using VapourSynth with super resolution and interpolation models and speeding them up with TensorRT.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

VSGAN-tensorrt-docker

Repository to use super resolution models and video frame interpolation models and also trying to speed them up with TensorRT. This repository contains the fastest inference code that you can find, at least I am trying to archive that. Not all codes can use TensorRT due to various reasons, but I try to add that if it works. Further model architectures are planned to be added later on.

Table of contents


Currently working networks:

Onnx files can be found here.

Also used:

Usage

The following docker requires the latest Nvidia driver (560+). After that, follow the following steps:

WARNING FOR PEOPLE WITHOUT AVX512: Instead of using styler00dollar/vsgan_tensorrt:latest, which I build with my 7950x and thus with all AVX, use styler00dollar/vsgan_tensorrt:latest_no_avx512 in compose.yaml to avoid Illegal instruction (core dumped) which is mentioned in this issue.

AND AS A FINAL INFO, Error opening input file pipe: IS NOT A REAL ERROR MESSAGE. That means invalid data got piped into ffmpeg and can be piped error messages for example. To see the actual error messages and what got piped, you can use vspipe -c y4m inference.py -.

Quickstart:

# if you have Windows, install Docker Desktop https://www.docker.com/products/docker-desktop/

# if you have Arch, install the following dependencies
yay -S docker nvidia-docker nvidia-container-toolkit docker-compose docker-buildx

# run the docker with docker-compose
# you need to be inside the vsgan folder with cli before running the following step, git clone repo and cd into it
# go into the vsgan folder, inside that folder should be compose.yaml, run this command
# you can adjust folder mounts in the yaml file
docker-compose run --rm vsgan_tensorrt

There are now multiple containers to choose from, if you don't want the default, then edit compose.yaml and set a different tag image: styler00dollar/vsgan_tensorrt:x prior to running docker-compose run --rm vsgan_tensorrt.

  • latest: Default docker with everything. Trying to keep everything updated and fixed.
  • latest_no_avx512 is for cpus without avx512 support, otherwise it just crashes if you try to run avx512 binaries on cpus without such support. Use this if your cpu does not support all instruction sets.
  • minimal: Bare minimum to run ffmpeg, mlrt and a few video readers.
docker image compressed download extracted container short description
styler00dollar/vsgan_tensorrt:latest 10gb 19gb default latest with trt10.6
styler00dollar/vsgan_tensorrt:latest_no_avx512 10gb 18gb trt10.5 without avx512
styler00dollar/vsgan_tensorrt:trt9.3 8gb 15gb trt9.3 use bfdb96a with this docker
styler00dollar/vsgan_tensorrt:trt9.3_no_avx512 8gb 15gb trt9.3 without avx512 use bfdb96a with this docker
styler00dollar/vsgan_tensorrt:minimal 5gb 10gb trt10.4 + ffmpeg + mlrt + ffms2 + lsmash + bestsource

Piping usage:

vspipe -c y4m inference.py - | ffmpeg -i pipe: example.mkv -y

If docker does not want to start, try this before you use docker:

sudo systemctl start docker

Linux docker autostart:

sudo systemctl enable --now docker

The following stuff is for people who want to run things from scratch. Manual ways of downloading the docker image:

# Download prebuild image from dockerhub (recommended)
docker pull styler00dollar/vsgan_tensorrt:latest

# if you have `unauthorized: authentication required` problems, download the docker with
git clone https://github.com/NotGlop/docker-drag
cd docker-drag
python docker_pull.py styler00dollar/vsgan_tensorrt:latest
docker load -i styler00dollar_vsgan_tensorrt.tar

Manually building docker image from scratch:

# Build docker manually (only required if you want to build from scratch)
# This step is not needed if you already downloaded the docker and is only needed if yo
# want to build it from scratch. Keep in mind that you need to set env variables in windows differently and
# this command will only work in linux. Run that inside that directory
DOCKER_BUILDKIT=1 sudo docker build -t styler00dollar/vsgan_tensorrt:latest .
# If you want to rebuild from scratch or have errors, try to build without cache
DOCKER_BUILDKIT=1 sudo docker build --no-cache -t styler00dollar/vsgan_tensorrt:latest .

Manually run docker:

# you need to be inside the vsgan folder with cli before running the following step, git clone repo and cd into it
# the folderpath before ":" will be mounted in the path which follows afterwards
# contents of the vsgan folder should appear inside /workspace/tensorrt

sudo docker run --privileged --gpus all -it --rm -v /home/vsgan_path/:/workspace/tensorrt styler00dollar/vsgan_tensorrt:latest

# Windows is mostly similar, but the path needs to be changed slightly:
Example for C://path
docker run --privileged --gpus all -it --rm -v /mnt/c/path:/workspace/tensorrt styler00dollar/vsgan_tensorrt:latest
docker run --privileged --gpus all -it --rm -v //c/path:/workspace/tensorrt styler00dollar/vsgan_tensorrt:latest

Usage example

Small minimalistic example of how to configure inference. If you only want to process one video, then edit video path in inference.py

video_path = "test.mkv"

and then afterwards edit inference_config.py.

Small example for upscaling with TensorRT:

import sys
import os

sys.path.append("/workspace/tensorrt/")
import vapoursynth as vs

core = vs.core
vs_api_below4 = vs.__api_version__.api_major < 4
core.num_threads = 8

core.std.LoadPlugin(path="/usr/local/lib/libvstrt.so")


def inference_clip(video_path="", clip=None):
    clip = core.bs.VideoSource(source=video_path)

    clip = vs.core.resize.Bicubic(clip, format=vs.RGBH, matrix_in_s="709")  # RGBS means fp32, RGBH means fp16
    clip = core.trt.Model(
        clip,
        engine_path="/workspace/tensorrt/2x_AnimeJaNai_V2_Compact_36k_op18_fp16_clamp.engine",  # read readme on how to build engine
        num_streams=2,
    )
    clip = vs.core.resize.Bicubic(clip, format=vs.YUV420P8, matrix_s="709")  # you can also use YUV420P10 for example

    return clip

Small example for rife interpolation with TensorRT without scene change detection:

import sys
import vapoursynth as vs
from src.rife_trt import rife_trt

sys.path.append("/workspace/tensorrt/")
core = vs.core
core.num_threads = 4

core.std.LoadPlugin(path="/usr/local/lib/libvstrt.so")


def inference_clip(video_path):
    clip = core.bs.VideoSource(source=video_path)

    clip = core.resize.Bicubic(
        clip, format=vs.RGBS, matrix_in_s="709"
    )  # RGBS means fp32, RGBH means fp16

    # interpolation
    clip = rife_trt(
        clip,
        multi=2,
        scale=1.0,
        device_id=0,
        num_streams=2,
        engine_path="/workspace/tensorrt/rife414_ensembleTrue_op18_fp16_clamp_sim.engine",  # read readme on how to build engine
    )

    clip = core.resize.Bicubic(clip, format=vs.YUV420P8, matrix_s="709")
    return clip

More examples in custom_scripts/.

Then use the commands above to render. For example:

vspipe -c y4m inference.py - | ffmpeg -i pipe: example.mkv

Video will be rendered without sound and other attachments. You can add that manually to the ffmpeg command.

To process videos in batch and copy their properties like audio and subtitle to another file, you need to use main.py. Edit filepaths and file extention:

input_dir = "/workspace/tensorrt/input/"
output_dir = "/workspace/tensorrt/output/"
files = glob.glob(input_dir + "/**/*.webm", recursive=True)

and configure inference_config.py like wanted. Afterwards just run

python main.py

Individual examples

More parameter documentation can be found in the plugin repositories.

core.std.LoadPlugin(path="/usr/lib/x86_64-linux-gnu/libffms2.so")
clip = core.ffms2.Source(source=video_path)
clip = core.lsmas.LWLibavSource(source=video_path)
clip = core.bs.VideoSource(source=video_path) # recommended
clip = core.descale.Debilinear(clip, 1280, 720)
clip = core.resize.Bicubic(clip, format=vs.RGBS, matrix_in_s="709")
clip = core.resize.Bicubic(clip, width=1280, height=720,, format=vs.RGBS, matrix_in_s="709")
  • Clamp 0-1
clip = core.akarin.Expr(clip, "x 0 1 clamp")
clip = clip.std.Expr("x 0 max 1 min")
clip = core.std.Limiter(clip, max=1, planes=[0,1,2])
clip = core.vmaf.Metric(clip, offs1, feature=2)
  • Scene Detect
clip = core.misc.SCDetect(clip=clip, threshold=0.100)

from src.scene_detect import scene_detect
clip = scene_detect(clip, fp16=True, thresh=0.85, model=12)
  • TensorRT inference: vstrt
core.std.LoadPlugin(path="/usr/local/lib/libvstrt.so")
clip = core.trt.Model(
    clip,
    engine_path="/workspace/tensorrt/cugan.engine",
    tilesize=[854, 480],
    overlap=[0, 0],
    num_streams=4,
)
core.std.LoadPlugin(path="/usr/local/lib/libvstrt.so")
strength = 10.0
noise_level = clip.std.BlankClip(format=vs.GRAYS, color=strength / 100)
clip = core.trt.Model(
    [clip, noise_level],
    engine_path="dpir.engine",
    tilesize=[1280, 720],
    num_streams=2,
)
core.std.LoadPlugin(path="/usr/local/lib/libvsort.so")
clip = core.ort.Model(clip, "/workspace/tensorrt/2x_ModernSpanimationV2_clamp_op20_fp16_onnxslim.onnx", provider="CUDA", fp16=True, num_streams=2)
# recommended for accuracy
from vsrife import rife
clip = rife(clip, trt=True, num_streams=2, model="4.22", sc=False)

# recommended for maximum speed, but differs from original model and may have visible artefacts, more info below
from src.rife_trt import rife_trt
clip = rife_trt(clip, multi=2, scale=1.0, device_id=0, num_streams=2, engine_path="/workspace/tensorrt/rife46.engine")
core.std.LoadPlugin(path="/usr/local/lib/x86_64-linux-gnu/libawarpsharp2.so")
clip = core.warp.AWarpSharp2(clip, thresh=128, blur=2, type=0, depth=[16, 8, 8], chroma=0, opt=True, planes=[0,1,2], cplace="mpeg1")
clip = core.cas.CAS(clip, sharpness=0.5)
import vs_colorfix
clip = vs_colorfix.average(clip, ref, radius=10, planes=[0, 1, 2], fast=False)
core.std.LoadPlugin(path="/usr/local/lib/x86_64-linux-gnu/libmvtools.so")
core.std.LoadPlugin(path="/usr/local/lib/x86_64-linux-gnu/libfillborders.so")
core.std.LoadPlugin(path="/usr/local/lib/x86_64-linux-gnu/libmotionmask.so")
core.std.LoadPlugin(path="/usr/local/lib/x86_64-linux-gnu/libtemporalmedian.so")
from vs_temporalfix import vs_temporalfix
clip = vs_temporalfix(clip, strength=400, tr=6, exclude="[10 20]", debug=False)
from src.utils import FastLineDarkenMOD
clip = FastLineDarkenMOD(clip)

vs-mlrt (C++ TRT)

You need to convert onnx models into engines. You need to do that on the same system where you want to do inference. Download onnx models from here or from my Github page. Inside the docker, you do one of the following commands:

Good default choice:

trtexec --bf16 --fp16 --onnx=model.onnx --minShapes=input:1x3x8x8 --optShapes=input:1x3x720x1280 --maxShapes=input:1x3x1080x1920 --saveEngine=model.engine --tacticSources=+CUDNN,-CUBLAS,-CUBLAS_LT --skipInference --useCudaGraph --noDataTransfers --builderOptimizationLevel=5

If you have the vram to fit the model multiple times, add --infStreams.

trtexec --bf16 --fp16 --onnx=model.onnx --minShapes=input:1x3x8x8 --optShapes=input:1x3x720x1280 --maxShapes=input:1x3x1080x1920 --saveEngine=model.engine --tacticSources=+CUDNN,-CUBLAS,-CUBLAS_LT --skipInference --useCudaGraph --noDataTransfers --builderOptimizationLevel=5 --infStreams=4

DPIR (color) needs 4 channels.

trtexec --bf16 --fp16 --onnx=model.onnx --minShapes=input:1x4x8x8 --optShapes=input:1x4x720x1280 --maxShapes=input:1x4x1080x1920 --saveEngine=model.engine --tacticSources=+CUDNN,-CUBLAS,-CUBLAS_LT --skipInference --useCudaGraph --noDataTransfers --builderOptimizationLevel=5

Warning: Rife with TensorRT is broken without workarounds in every implementation (mlrt, torch_tensorrt, onnxruntime trt,...), even with fp32, and results in wobbly lines and artefacts during panning scenes. The amount of artefacts seem to depend on the rife version and it probably never worked properly once since I saw them with TensorRT 9 and 10. HolyWu/vs-rife fixed it by running the warp (which mainly is just the grid sample operator) with torch while having the other parts of the network run with TensorRT and that ensures a correct image. Unless Nvidia fixes it, it will stay broken with core.trt. If small artefacts are not a dealbreaker, you can run engines built with trtexec and with core.trt like usual for maximum vapoursynth performance, but I would strongly recommend to use vsrife instead. vsrife is currently the only existing implementation that is able to correctly run rife with TensorRT, but is slower than using mlrt. A small example on how to use vsrife would be clip = rife(clip, trt=True).

Rife v1 needs 8 channels.

trtexec --bf16 --fp16 --onnx=model.onnx --minShapes=input:1x8x64x64 --optShapes=input:1x8x720x1280 --maxShapes=input:1x8x1080x1920 --saveEngine=model.engine --tacticSources=+CUDNN,-CUBLAS,-CUBLAS_LT --skipInference --useCudaGraph --noDataTransfers --builderOptimizationLevel=5

Rife v2 needs 7 channels. Set the same shape everywhere to avoid build errors.

trtexec --bf16 --fp16 --onnx=model.onnx --minShapes=input:1x7x1080x1920 --optShapes=input:1x7x1080x1920 --maxShapes=input:1x7x1080x1920 --saveEngine=model.engine --tacticSources=+CUDNN,-CUBLAS,-CUBLAS_LT --skipInference --useCudaGraph --noDataTransfers --builderOptimizationLevel=5

My Shuffle Span has a static shape and needs dynamic conv to be in fp32 for lower precision to work.

trtexec --bf16 --fp16 --onnx=sudo_shuffle_span_op20_10.5m_1080p_onnxslim.onnx --saveEngine=sudo_shuffle_span_op20_10.5m_1080p_onnxslim.engine --tacticSources=+CUDNN,-CUBLAS,-CUBLAS_LT --skipInference --useCudaGraph --noDataTransfers --builderOptimizationLevel=5 --infStreams=4 --layerPrecisions=/dynamic/Conv:fp32 --precisionConstraints=obey

Put that engine path into inference_config.py.

Warnings:

  • Only add --bf16 if your GPU supports it, otherwise remove it. If model looks broken, remove --fp16.
  • Cugan with 3x scale requires same MIN/OPT/MAX shapes.
  • rvpV2 needs 6 channels, but does not support variable shapes.
  • If you use the FP16 onnx you need to use RGBH colorspace, if you use FP32 onnx you need to use RGBS colorspace in inference_config.py .
  • Engines are system specific, don't use across multiple systems.
  • Don't use reuse engines for different GPUs.
  • If you run out of memory, then you need to adjust the resolutions in that command. If your video is bigger than what you can input in the command, use tiling.
  • If you get segfault, reduce builderOptimizationLevel. Change can change it down to 1 to speed up the engine building, but may result in worse speeds.
  • If you set min, opt and max to the same resolution, it might result in a faster engine.

Deduplicated inference

Calculate similarity between frames with HomeOfVapourSynthEvolution/VapourSynth-VMAF and skip similar frames in interpolation tasks. The properties in the clip will then be used to skip similar frames.

from src.rife_trt import rife_trt

core.std.LoadPlugin(path="/usr/local/lib/libvstrt.so")


# calculate metrics
def metrics_func(clip):
    offs1 = core.std.BlankClip(clip, length=1) + clip[:-1]
    offs1 = core.std.CopyFrameProps(offs1, clip)
    return core.vmaf.Metric(clip, offs1, 2)

def inference_clip(video_path):
    interp_scale = 2
    clip = core.bs.VideoSource(source=video_path)

    # ssim
    clip_metric = vs.core.resize.Bicubic(
        clip, width=224, height=224, format=vs.YUV420P8, matrix_s="709"  # resize before ssim for speedup
    )
    clip_metric = metrics_func(clip_metric)
    clip_orig = core.std.Interleave([clip] * interp_scale)

    # interpolation
    clip = rife_trt(
        clip,
        multi=interp_scale,
        scale=1.0,
        device_id=0,
        num_streams=2,
        engine_path="/workspace/tensorrt/rife414_ensembleTrue_op18_fp16_clamp_sim.engine",
    )

    # skip frames based on calculated metrics
    # in this case if ssim > 0.999, then copy frame
    clip = core.akarin.Select([clip, clip_orig], clip_metric, "x.float_ssim 0.999 >")

    return clip

There are multiple different metrics that can be used, but be aware that you may need to adjust the threshold metric value in vfi_inference.py, since they work differently. SSIM has a maximum of 1 and PSNR has a maximum of infinity. I would recommend leaving the defaults unless you know what you do.

# 0 = PSNR, 1 = PSNR-HVS, 2 = SSIM, 3 = MS-SSIM, 4 = CIEDE2000
return core.vmaf.Metric(clip, offs1, 2)

Shot Boundary Detection

Detection is implemented in various different ways. To use traditional scene change you can do:

clip_sc = core.misc.SCDetect(
  clip=clip,
  threshold=0.100
)

Afterwards you can call clip = core.akarin.Select([clip, clip_orig], clip_sc, "x._SceneChangeNext 1 0 ?") to apply it.

Or use models like this. Adjust thresh to a value between 0 and 1, higher means to ignore with less confidence.

clip_sc = scene_detect(
    clip,
    fp16=True,
    thresh=0.5,
    model=3,
)

Warning: Keep in mind that different models may require a different thresh to be good.

The rife models mean, that flow gets used as an additional input into the classification model. That should increase stability without major speed decrease. Models that are not linked will be converted later.

Available onnx files:

  • efficientnetv2_b0 (256px) (fp16 fp32)
  • efficientnetv2_b0+rife46 (256px) (fp16 fp32)
  • efficientformerv2_s0 (224px) (fp16 fp32)
  • efficientformerv2_s0+rife46 (224px) (fp16 fp32)
  • swinv2_small (256px) (fp16 fp32)
  • swinv2_small+rife46 (256px) (fp16 fp32)

Other models I trained but are not available due to various reasons:

  • hornet_tiny_7x7
  • renset50
  • STAM
  • volo_d1
  • tf_efficientnetv2_xl_in21k
  • resnext50_32x4d
  • nfnet_f0
  • swsl_resnet18
  • poolformer_m36
  • densenet121
  • TimeSformer
  • maxvit_small
  • maxvit_small+rife46
  • regnetz_005
  • repvgg_b0
  • resnetrs50
  • resnetv2_50
  • rexnet_100

Interesting observations:

  • Applying means/stds seemingly worsened results, despite people doing that as standard practise.
  • Applying image augmentation worsened results.
  • Training with higher batchsize made detections a little more stable, but maybe that was placebo and a result of more finetuning.

Comparison to traditional methods:

  • wwxd and scxvid suffer from overdetection (at least in drawn animation).
  • The json that master-of-zen/Av1an produces with --sc-only --sc-method standard --scenes test.json returns too little scene changes. Changing the method does not really influence a lot. Not reliable enough for vfi.
  • I can't be bothered to Breakthrough/PySceneDetect get working with vapousynth with FrameEval and by default it only works with video or image sequence as input. I may try in the future, but I don't understand why I cant just input two images.
  • misc.SCDetect seemed like the best traditional vapoursynth method that does currently exist, but I thought I could try to improve. It struggles harder with similar colors and tends to skip more changes compared to methods.

Decided to only do scene change inference with ORT with TensorRT backend to keep code small and optimized.

Example usage:

from src.scene_detect import scene_detect
from src.rife_trt import rife_trt

core.std.LoadPlugin(path="/usr/local/lib/libvstrt.so")


clip_sc = scene_detect(
    clip,
    fp16=True,
    thresh=0.5,
    model=3,
)

clip = rife_trt(
    clip,
    multi=2,
    scale=1.0,
    device_id=0,
    num_streams=2,
    engine_path="/workspace/tensorrt/rife414_ensembleTrue_op18_fp16_clamp_sim.engine",
)

clip_orig = core.std.Interleave([clip_orig] * 2)  # 2 means interpolation factor here
clip = core.akarin.Select([clip, clip_orig], clip_sc, "x._SceneChangeNext 1 0 ?")

multi-gpu

Thanks to tepete who figured it out, there is also a way to do inference on multipe GPUs.

stream0 = core.std.SelectEvery(core.trt.Model(clip, engine_path="models/engines/model.engine", num_streams=2, device_id=0), cycle=3, offsets=0)
stream1 = core.std.SelectEvery(core.trt.Model(clip, engine_path="models/engines/model.engine", num_streams=2, device_id=1), cycle=3, offsets=1)
stream2 = core.std.SelectEvery(core.trt.Model(clip, engine_path="models/engines/model.engine", num_streams=2, device_id=2), cycle=3, offsets=2)
clip = core.std.Interleave([stream0, stream1, stream2])

ddfi

To quickly explain what ddfi is, the repository Mr-Z-2697/ddfi-rife deduplicates frames and interpolates between frames. Normally, frames which are duplicated can create a stuttering visual effect and to mitigate that, a higher interpolation factor is used on scenes which have a duplicated frames to compensate.

Visual examples from that repository:

comp.mp4

Example usage is in custom_scripts/ddfi_rife_dedup_scene_change/. As a quick summary, you need to do two processing passes. One pass to calculate metrics and another to use interpolation combined with VFRToCFR. You need to use deduped_vfi.py similar to how you used main.py.

VFR

Warning: Using variable refresh rate video input will result in desync errors. To check if a video is do

ffmpeg -i video_Name.mp4 -vf vfrdet -f null -

and look at the final line. If it is not zero, then it means it is variable refresh rate. Example:

[Parsed_vfrdet_0 @ 0x56518fa3f380] VFR:0.400005 (15185/22777) min: 1801 max: 3604)

To go around this issue, specify fpsnum and fpsden in inference_config.py

clip = core.ffms2.Source(source='input.mkv', fpsnum = 24000, fpsden = 1001, cache=False)

or convert everything to constant framerate with ffmpeg.

ffmpeg -i video_input.mkv -fps_mode cfr -crf 10 -c:a copy video_out.mkv

or use my vfr_to_cfr.py to process a folder.

Benchmarks

Warnings:

  • Keep in mind that these benchmarks can get outdated very fast due to rapid code development and configurations.
  • The default is ffmpeg.
  • ModifyFrame is depricated. Trying to use FrameEval everywhere and is used by default.
  • TensorRT docker version and ONNX opset seem to influence speed but that wasn't known for quite some time. I have a hard time pinpointing which TensorRT and ONNX opset was used. Take benchmark as a rough indicator.
  • Colab may change hardware like CPU at any point.
  • Sometimes it takes a very long time to reach the final speed. It can happen that not enough time was waited.
  • 3090¹ (+11900k) benches most likely were affected by power lowered power limit.
  • 3090² (+5950x) system provided by Piotr Rencławowicz for benchmarking purposes.
  • int8 does not automatically mean usable model. It can differ from normal inference quite a lot without adjusting the model.
  • thread_queue_size means -thread_queue_size 2488320.
  • "*" indicates benchmarks which were done with vspipe file.py -p . instead of piping into ffmpeg and rendering to avoid cpu bottleneck.
Compact (2x) 480p 720p 1080p
rx470 vs+ncnn (np+no tile+tta off) 2.7 1.6 0.6
1070ti vs+ncnn (np+no tile+tta off) 4.2 2 0.9
1070ti (ONNX-TRT+FrameEval) 12 6.1 2.8
1070ti (C++ TRT+FrameEval+num_streams=6) 14 6.7 3
3060ti (ONNX-TRT+FrameEval) ? 7.1 3.2
3060ti (C++ TRT+FrameEval+num_streams=5) ? 15.97 7.83
3060ti VSGAN 2x ? 3.6 1.77
3060ti ncnn (Windows binary) 2x ? 4.2 1.2
3060ti Joey 2x ? 0.87 0.36
3070 (ONNX-TRT+FrameEval) 20 7.55 3.36
3090¹ (ONNX-TRT+FrameEval) ? ? 6.7
3090² (vs+TensorRT8.4+C++ TRT+vs_threads=20+num_streams=20+opset15) 105 47 21
2x3090² (vs+TensorRT8.4+C++ TRT+num_streams=22+opset15) 133 55 23
V100 (Colab) (vs+CUDA) 8.4 3.8 1.6
V100 (Colab) (vs+TensorRT8+ONNX-TRT+FrameEval) 8.3 3.8 1.7
V100 (Colab High RAM) (vs+CUDA+FrameEval) 29 13 6
V100 (Colab High RAM) (vs+TensorRT7+ONNX-TRT+FrameEval) 21 12 5.5
V100 (Colab High RAM) (vs+TensorRT8.2GA+ONNX-TRT+FrameEval) 21 12 5.5
V100 (Colab High RAM) (vs+TensorRT8.4+C++ TRT+num-streams=15) ? ? 6.6
A100 (Colab) (vs+CUDA+FrameEval) 40 19 8.5
A100 (Colab) (vs+TensorRT8.2GA+ONNX-TRT+FrameEval) 44 21 9.5
A100 (Colab) (vs+TensorRT8.2GA+C++ TRT+ffmpeg+FrameEval+num_streams=50) 52.72 24.37 11.84
A100 (Colab) (vs+TensorRT8.2GA) (C++ TRT+x264 (--opencl)+FrameEval+num_streams=50) 57.16 26.25 12.42
A100 (Colab) (vs+onnx+FrameEval) 26 12 4.9
A100 (Colab) (vs+quantized onnx+FrameEval) 26 12 5.7
A100 (Colab) (jpg+CUDA) 28.2 (9 Threads) 28.2 (7 Threads) 9.96 (4 Threads)
4090 (TRT9.3+num_streams=3+(fp16+bf16)+RGBH+op18) ? ? / 92.3* ? / 41.5*
6700xt (vs_threads=4+mlrt ncnn) ? / 7.7* ? / 3.25* ? / 1.45*
Compact (4x) 480p 720p 1080p
1070ti TensorRT8 docker (ONNX-TensorRT+FrameEval) 11 5.6 X
3060ti TensorRT8 docker (ONNX-TensorRT+FrameEval) ? 6.1 2.7
3060ti TensorRT8 docker 2x (C++ TRT+FrameEval+num_streams=5) ? 11 5.24
3060ti VSGAN 4x ? 3 1.3
3060ti ncnn (Windows binary) 4x ? 0.85 0.53
3060ti Joey 4x ? 0.25 0.11
A100 (Colab) (vs+CUDA+FrameEval) 12 5.6 2.9
A100 (Colab) (jpg+CUDA) ? ? 3 (4 Threads)
4090³ (TensorRT8.4GA+10 vs threads+fp16) ? ? / 56* (5 streams) ? / 19.4* (2 streams)
UltraCompact (2x) 480p 720p 1080p
4090 (TRT9.1+num_threads=4+num_streams=2+(fp16+bf16)+RGBH+op18) ? ? / 113.7* ? / 52.7*
6700xt (vs_threads=4+mlrt ncnn) ? / 14.5* ? / 6.1* ? / 2.76*
cugan (2x) 480p 720p 1080p
1070ti (vs+TensorRT8.4+ffmpeg+C++ TRT+num_streams=2+no tiling+opset13) 6 2.7 OOM
V100 (Colab) (vs+CUDA+ffmpeg+FrameEval) 7 3.1 ?
V100 (Colab High RAM) (vs+CUDA+ffmpeg+FrameEval) 21 9.7 4
V100 (Colab High RAM) (vs+TensorRT8.4+ffmpeg+C++ TRT+num_streams=3+no tiling+opset13) 30 14 6
A100 (Colab High RAM) (vs+TensorRT8.4+x264 (--opencl)+C++ TRT+vs threads=8+num_streams=8+no tiling+opset13) 53.8 24.4 10.9
3090² (vs+TensorRT8.4+ffmpeg+C++ TRT+vs_threads=8+num_streams=5+no tiling+opset13) 79 35 15
2x3090² (vs+TensorRT8.4+ffmpeg+C++ TRT+vs_threads=12+num_streams=5+no tiling+opset13) 131 53 23
4090 (TRT9.1+num_threads=4+num_streams=2+(fp16+bf16)+RGBH+op18) ? ? / 51* ? / 22.7*
6700xt (vs_threads=4+mlrt ncnn) ? / 3.3* ? / 1.3* OOM (512px tiling ? / 0.39*)
ESRGAN 4x (64mb) (23b+64nf) 480p 720p 1080p
1070ti TensorRT8 docker (Torch-TensorRT+ffmpeg+FrameEval) 0.5 0.2 >0.1
3060ti TensorRT8 docker (Torch-TensorRT+ffmpeg+FrameEval) ? 0.7 0.29
3060ti Cupscale (Pytorch) ? 0.13 0.044
3060ti Cupscale (ncnn) ? 0.1 0.04
3060ti Joey ? 0.095 0.043
V100 (Colab) (Torch-TensorRT8.2GA+ffmpeg+FrameEval) 1.8 0.8 ?
V100 (Colab High VRAM) (C++ TensorRT8.2GA+x264 (--opencl)+FrameEval+no tiling) 2.46 OOM (OpenCL) OOM (OpenCL)
V100 (Colab High VRAM) (C++ TensorRT8.2GA+x264+FrameEval+no tiling) 2.49 1.14 0.47
A100 (Colab) (Torch-TensorRT8.2GA+ffmpeg+FrameEval) 5.6 2.6 1.1
3090² (C++ TRT+vs_threads=20+num_threads=2+no tiling+opset14) 3.4 1.5 0.7
2x3090² (C++ TRT+vs_threads=20+num_threads=2+no tiling+opset14) 7.0 3.2 1.5
4090 (TRT9.1+num_threads=4+num_streams=2+(fp16+bf16)+RGBS+op14) ? ? / 2.6* ? / 1.2*

Note: The offical RealESRGAN-6b model uses 6 blocks for the anime model and uses the ESRGAN architecture.

RealESRGAN (4x) (6b+64nf) 480p 720p 1080p
3060ti (vs+TensorRT8+ffmpeg+C++ TRT+num_streams=2) ? 1.7 0.75
V100 (Colab High RAM) (vs+TensorRT8.2GA+x264 (--opencl)+C++ TRT+num_streams=1+no tiling) 6.82 3.15 OOM (OpenCL)
V100 (Colab High RAM) (vs+TensorRT8.2GA+x264+C++ TRT+num_streams=1+no tiling) ? ? 1.39
A100 (vs+TensorRT8.2GA+x264 (--opencl)+C++ TRT+num_streams=3+no tiling) 14.65 6.74 2.76
3090² (C++ TRT+vs_threads=20+num_threads=2+no tiling+opset14) 11 4.8 2.3
2x3090² (C++ TRT+vs_threads=10+num_threads=2+no tiling+opset14) 22 9.5 4.2
4090 (TRT9.1+num_threads=4+num_streams=2+(fp16+bf16)+RGBH+op18) ? ? / 8.8* ? / 3.9*

Rife v2 refers to a custom implementation made by WolframRhodium. I would recommend to avoid int8 for 1080p, the warping looks a bit broken. int8 seems usable with 720p and looks closer to bf16/fp16. TRT10.0-10.2 is slower than 9.3 and thus not recommended. TRT10.3 fixed GridSample and thus is recommended again. Windows seems slower than Linux by quite a margin. Not all show major improvement with above 3 streams. There mostly seems to be no difference between level 3 and 5.

Rife4+vs (ensemble False) 480p 720p 1080p
Rife 4.6 ------- ------- -------
4090 rife4.6 (Win11 vs-ncnn+num_streams=3+RGBS) ? ? ? / 134.3*
4090 rife4.6 (Arch KDE vs-rife+TRT10 (level 5)+num_streams=3+RGBH) ? ? / 827.1* ? / 357.9*
4090 rife4.6 (Win11 mlrt+TRT9.2 (level 3)+num_streams=3+RGBH) ? ? ? / 294.5*
4090 rife4.6 (Win11 VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op18) ? ? ? / 372.7*
4090 rife4.6 (Manjaro Gnome VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op18) ? ? / 1083.3* ? / 469.9*
4090 rife4.6 v2 (Win11 mlrt+TRT9.2 (level 3)+num_streams=3+RGBH) ? ? ? / 442.4*
4090 rife4.6 v2 (Win11 mlrt+TRT9.2 (level 3)+num_streams=8+RGBH) ? ? ? / 480.2*
4090 rife4.6 v2 (Arch KDE VSGAN+TRT9.3 (level 5)+num_streams=3+RGBH+op16 (fp16 converted mlrt onnx)) ? ? / 1228.4* ? / 511*
4090 rife4.6 v2 (Pop!_OS VSGAN+TRT10.3 (level 5)+num_streams=3+RGBH+op16 (fp16 converted mlrt onnx)) ? ? / 1364* ? / 554.2*
Steam Deck rife4.6 (ncnn+RGBS) ? ? / 19.2* ? / 8.8*
Rife 4.15 ------- ------- -------
4090 rife4.15 (Win11 vs-ncnn+num_streams=3+RGBS) ? ? ? / 115.2*
4090 rife4.15 (Arch KDE vs-rife+TRT10 (level 5)+num_streams=3+RGBH) ? ? / 506.3* ? / 204.2*
4090 rife4.15 (Win11 mlrt+TRT9.2 (level 3)+num_streams=3+RGBH) ? ? ? / 237.7*
4090 rife4.15 (Win11 VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op19) ? ? ? / 205*
4090 rife4.15 (Arch Gnome VSGAN (level 5)+TRT9.3+num_streams=3+(fp16+bf16)+RGBH+op19) ? ? ? / 245.5*
4090 rife4.15 v2 (Win11 mlrt+TRT9.2 (level 3)+num_streams=3+RGBH) ? ? ? / 276.8*
4090 rife4.15 v2 (Arch KDE VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op20) ? ? / 930.9* ? / 360.1*
4090 rife4.15 v2 (Pop!_OS VSGAN+TRT10.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op20) ? ? / 954.8* ? / 359.4*
Rife 4.15 (int8) ------- ------- -------
4090 rife4.15 v2 (Arch KDE VSGAN+TRT9.3 (level 5)+num_streams=3+(int8+fp16+bf16)+RGBH+op20) ? ? / 995.3* ? / 424*
4090 rife4.15 v2 (Arch KDE VSGAN+TRT9.3 (level 5)+num_streams=8+(int8+fp16+bf16)+RGBH+op20) ? ? / 1117.6* ? / 444.5*
Rife4+vs (ensemble True) 480p 720p 1080p
Rife 4.6 ------- ------- -------
4090 rife4.6 (Win11 vs-ncnn+num_streams=3+RGBS) ? ? ? / 89.5*
4090 rife4.6 (Arch KDE vs-rife+TRT10 (level 5)+num_streams=3+RGBH) ? ? / 649.6* ? / 237.7*
4090 rife4.6 (Win11 mlrt+TRT9.3 (level 3)+num_streams=3) ? ? ? / 226.7*
4090 rife4.6 (Win11 VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op18) ? ? ? / 228.7*
4090 rife4.6 (Manjaro Gnome VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op18) ? ? / 671.4* ? / 303.8*
4090 rife4.6 v2 (Win11 mlrt+TRT9.3 (level 3)+num_streams=3) ? ? ? / 251.8*
4090 rife4.6 v2 (Arch KDE VSGAN (level 5)+TRT9.3+num_streams=3+RGBH+op16 (fp16 converted mlrt onnx)) ? ? / 843.8* ? / 346.2*
Rife 4.15 ------- ------- -------
4090 rife4.15 (Win11 vs-ncnn+num_streams=3+RGBS) ? ? ? / 67*
4090 rife4.15 (Arch KDE vs-rife+TRT10 (level 5)+num_streams=3+RGBH) ? ? / 339.6* ? / 142.2*
4090 rife4.15 (Win11 mlrt+TRT9.2 (level 3)+num_streams=3+RGBH) ? ? ? / 133.4*
4090 rife4.15 (Win11 VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op19) ? ? ? / 139.8*
4090 rife4.15 (Manjaro Gnome VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op19) ? ? / 348.5* ? / 149.6*
4090 rife4.15 v2 (Win11 mlrt+TRT9.2 (level 3)+num_streams=3+RGBH) ? ? ? / 147.3*
4090 rife4.15 v2 (Arch KDE VSGAN+TRT9.3 (level 5)+num_streams=3+(fp16+bf16)+RGBH+op20) ? ? / 463.1* ? / 181.3*
Rife 4.15 (int8) ------- ------- -------
4090 rife4.15 v2 (Arch KDE VSGAN+TRT9.3 (level 5)+num_streams=3+(int8+fp16+bf16)+RGBH+op20) ? ? / 557.5* ? / 210.6*
  • Benchmarks made with HolyWu version with threading and partial TensorRT and without setting tactic to JIT_CONVOLUTIONS and EDGE_MASK_CONVOLUTIONS due to performance penalty. I added a modified version as a plugin to VSGAN, but I need to add enhancements to my own repo later.
GMFSS_union 480p 720p 1080p
4090 (num_threads=8, num_streams=3, RGBH, TRT8.6, matmul_precision=medium) ? ? / 44.6* ? / 15.5*
GMFSS_fortuna_union 480p 720p 1080p
4090 (num_threads=8, num_streams=2, RGBH, TRT8.6.1, matmul_precision=medium) ? ? / 50.4* ? / 16.9*
4090 (num_threads=8, num_streams=2, RGBH, TRT8.6.1, matmul_precision=medium, @torch.compile(mode="default", fullgraph=True)) ? ? / 50.6* ? / 17*
DPIR 480p 720p 1080p
4090 (TRT9.1+num_threads=4+num_streams=2+(fp16+bf16)+RGBH+op18) ? ? / 54* ? / 24.4*

License

This code uses code from other repositories, but the code I wrote myself is under BSD3.

About

Using VapourSynth with super resolution and interpolation models and speeding them up with TensorRT.

License:BSD 3-Clause "New" or "Revised" License


Languages

Language:Python 64.1%Language:Dockerfile 35.8%Language:Shell 0.1%