Guest User

Untitled

a guest
Jun 22nd, 2026
90
0
Never
2
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 118.02 KB | None | 0 0
  1. __version__ = "3.23.1"
  2.  
  3. __all__ = [
  4. "Backend", "BackendV2",
  5. "Waifu2x", "Waifu2xModel",
  6. "DPIR", "DPIRModel",
  7. "RealESRGAN", "RealESRGANModel",
  8. "RealESRGANv2", "RealESRGANv2Model",
  9. "CUGAN",
  10. "RIFE", "RIFEModel", "RIFEMerge",
  11. "SAFA", "SAFAModel", "SAFAAdaptiveMode",
  12. "SCUNet", "SCUNetModel",
  13. "SwinIR", "SwinIRModel",
  14. "ArtCNN", "ArtCNNModel",
  15. "inference",
  16. "flexible_inference"
  17. ]
  18.  
  19. import copy
  20. from dataclasses import dataclass, field
  21. import enum
  22. from fractions import Fraction
  23. import math
  24. import os
  25. import os.path
  26. import platform
  27. import subprocess
  28. import sys
  29. import tempfile
  30. import time
  31. import typing
  32. import warnings
  33. import zlib
  34.  
  35. import vapoursynth as vs
  36. from vapoursynth import core
  37.  
  38.  
  39. def get_plugins_path() -> str:
  40. plugin_names = ("ov", "ort", "ncnn", "trt", "trt_rtx", "migx")
  41.  
  42. for plugin_name in plugin_names:
  43. try:
  44. path = getattr(core, plugin_name).Version()["path"]
  45. return os.path.dirname(path).decode()
  46. except AttributeError:
  47. continue
  48.  
  49. raise RuntimeError("vsmlrt: cannot load any filters")
  50.  
  51.  
  52. plugins_path: str = get_plugins_path()
  53. trtexec_path: str = os.path.join(plugins_path, "vsmlrt-cuda", "trtexec")
  54. migraphx_driver_path: str = os.path.join(plugins_path, "vsmlrt-hip", "migraphx-driver")
  55. tensorrt_rtx_path: str = os.path.join(plugins_path, "vsmlrt-cuda", "tensorrt_rtx")
  56. models_path: str = os.path.join(plugins_path, "models")
  57.  
  58.  
  59. class Backend:
  60. @dataclass(frozen=False)
  61. class ORT_CPU:
  62. """ backend for cpus """
  63.  
  64. num_streams: int = 1
  65. verbosity: int = 2
  66. fp16: bool = False
  67. fp16_blacklist_ops: typing.Optional[typing.Sequence[str]] = None
  68. output_format: int = 0 # 0: fp32, 1: fp16
  69.  
  70. # internal backend attributes
  71. supports_onnx_serialization: bool = True
  72.  
  73. @dataclass(frozen=False)
  74. class ORT_CUDA:
  75. """ backend for nvidia gpus
  76.  
  77. basic performance tuning:
  78. set fp16 = True (on RTX GPUs)
  79.  
  80. Semantics of `fp16`:
  81. Enabling `fp16` will use a built-in quantization that converts a fp32 onnx to a fp16 onnx.
  82. If the input video is of half-precision floating-point format,
  83. the generated fp16 onnx will use fp16 input.
  84. The output format can be controlled by the `output_format` option (0 = fp32, 1 = fp16).
  85.  
  86. Disabling `fp16` will not use the built-in quantization.
  87. However, if the onnx file itself uses fp16 for computation,
  88. the actual computation will be done in fp16.
  89. In this case, the input video format should match the input format of the onnx,
  90. and the output format is inferred from the onnx.
  91. """
  92.  
  93. device_id: int = 0
  94. cudnn_benchmark: bool = True
  95. num_streams: int = 1
  96. verbosity: int = 2
  97. fp16: bool = False
  98. use_cuda_graph: bool = False # preview, not supported by all models
  99. fp16_blacklist_ops: typing.Optional[typing.Sequence[str]] = None
  100. prefer_nhwc: bool = False
  101. output_format: int = 0 # 0: fp32, 1: fp16
  102. tf32: bool = False
  103.  
  104. # internal backend attributes
  105. supports_onnx_serialization: bool = True
  106.  
  107. @dataclass(frozen=False)
  108. class OV_CPU:
  109. """ backend for x86 cpus
  110.  
  111. basic performance tuning:
  112. set bf16 = True (on Zen4)
  113. increase num_streams
  114. """
  115.  
  116. fp16: bool = False
  117. num_streams: typing.Union[int, str] = 1
  118. bind_thread: bool = True
  119. fp16_blacklist_ops: typing.Optional[typing.Sequence[str]] = None
  120. bf16: bool = False
  121. num_threads: int = 0
  122.  
  123. # internal backend attributes
  124. supports_onnx_serialization: bool = True
  125.  
  126. @dataclass(frozen=False)
  127. class TRT:
  128. """ backend for nvidia gpus
  129.  
  130. basic performance tuning:
  131. set fp16 = True (on RTX GPUs)
  132. increase num_streams
  133. increase workspace
  134. set use_cuda_graph = True
  135. """
  136.  
  137. max_shapes: typing.Optional[typing.Tuple[int, int]] = None
  138. opt_shapes: typing.Optional[typing.Tuple[int, int]] = None
  139. fp16: bool = False
  140. device_id: int = 0
  141. workspace: typing.Optional[int] = None
  142. verbose: bool = False
  143. use_cuda_graph: bool = True
  144. num_streams: int = 1
  145. use_cublas: bool = False # cuBLAS + cuBLASLt
  146. static_shape: bool = True
  147. tf32: bool = False
  148. log: bool = True
  149.  
  150. # as of TensorRT 8.4, it can be turned off without performance penalty in most cases
  151. use_cudnn: bool = False # changed to False since vsmlrt.vpy 3.16
  152. use_edge_mask_convolutions: bool = True
  153. use_jit_convolutions: bool = True
  154. heuristic: bool = False # only supported on Ampere+ with TensorRT 8.5+
  155. output_format: int = 0 # 0: fp32, 1: fp16
  156. min_shapes: typing.Tuple[int, int] = (0, 0)
  157. faster_dynamic_shapes: bool = True
  158. force_fp16: bool = False
  159. builder_optimization_level: int = 3
  160. max_aux_streams: typing.Optional[int] = None
  161. short_path: typing.Optional[bool] = None # True on Windows by default, False otherwise
  162. bf16: bool = False
  163. custom_env: typing.Dict[str, str] = field(default_factory=lambda: {})
  164. custom_args: typing.List[str] = field(default_factory=lambda: [])
  165. engine_folder: typing.Optional[str] = None
  166. max_tactics: typing.Optional[int] = None
  167. tiling_optimization_level: int = 0
  168. l2_limit_for_tiling: int = -1
  169.  
  170. # internal backend attributes
  171. supports_onnx_serialization: bool = False
  172.  
  173. @dataclass(frozen=False)
  174. class OV_GPU:
  175. """ backend for nvidia gpus
  176.  
  177. basic performance tuning:
  178. set fp16 = True
  179. increase num_streams
  180. """
  181.  
  182. fp16: bool = False
  183. num_streams: typing.Union[int, str] = 1
  184. device_id: int = 0
  185. fp16_blacklist_ops: typing.Optional[typing.Sequence[str]] = None
  186.  
  187. # internal backend attributes
  188. supports_onnx_serialization: bool = True
  189.  
  190. @dataclass(frozen=False)
  191. class NCNN_VK:
  192. """ backend for vulkan devices
  193.  
  194. basic performance tuning:
  195. set fp16 = True (on modern GPUs)
  196. increase num_streams
  197. """
  198.  
  199. fp16: bool = False
  200. device_id: int = 0
  201. num_streams: int = 1
  202. output_format: int = 0 # 0: fp32, 1: fp16
  203.  
  204. # internal backend attributes
  205. supports_onnx_serialization: bool = True
  206.  
  207. @dataclass(frozen=False)
  208. class ORT_DML:
  209. """ backend for directml (d3d12) devices """
  210.  
  211. device_id: int = 0
  212. num_streams: int = 1
  213. verbosity: int = 2
  214. fp16: bool = False
  215. fp16_blacklist_ops: typing.Optional[typing.Sequence[str]] = None
  216. output_format: int = 0 # 0: fp32, 1: fp16
  217.  
  218. # internal backend attributes
  219. supports_onnx_serialization: bool = True
  220.  
  221. @dataclass(frozen=False)
  222. class MIGX:
  223. """ backend for amd gpus
  224.  
  225. basic performance tuning:
  226. set fp16 = True
  227. """
  228.  
  229. device_id: int = 0
  230. fp16: bool = False
  231. opt_shapes: typing.Optional[typing.Tuple[int, int]] = None
  232. fast_math: bool = True
  233. exhaustive_tune: bool = False
  234. num_streams: int = 1
  235. short_path: typing.Optional[bool] = None # True on Windows by default, False otherwise
  236. custom_env: typing.Dict[str, str] = field(default_factory=lambda: {})
  237. custom_args: typing.List[str] = field(default_factory=lambda: [])
  238. bf16: bool = False
  239.  
  240. # internal backend attributes
  241. supports_onnx_serialization: bool = False
  242.  
  243. @dataclass(frozen=False)
  244. class OV_NPU:
  245. """ backend for intel npus
  246. """
  247.  
  248. # internal backend attributes
  249. supports_onnx_serialization: bool = True
  250.  
  251. @dataclass(frozen=False)
  252. class ORT_COREML:
  253. """ backend for coreml """
  254. num_streams: int = 1
  255. verbosity: int = 0
  256. fp16: bool = False
  257. fp16_blacklist_ops: typing.Optional[typing.Sequence[str]] = None
  258. ml_program: int = 0
  259. output_format: int = 0 # 0: fp32, 1: fp16
  260.  
  261. # internal backend attributes
  262. supports_onnx_serialization: bool = True
  263.  
  264. @dataclass(frozen=False)
  265. class TRT_RTX:
  266. """ backend for nvidia rtx gpus
  267.  
  268. basic performance tuning:
  269. set fp16 = True
  270. increase num_streams
  271. increase workspace
  272. set use_cuda_graph = True
  273. """
  274.  
  275. fp16: bool = False
  276. device_id: int = 0
  277. workspace: typing.Optional[int] = None
  278. verbose: bool = False
  279. use_cuda_graph: bool = False
  280. num_streams: int = 1
  281.  
  282. static_shape: bool = True
  283. min_shapes: typing.Tuple[int, int] = (0, 0)
  284. opt_shapes: typing.Optional[typing.Tuple[int, int]] = None
  285. max_shapes: typing.Optional[typing.Tuple[int, int]] = None
  286.  
  287. use_cudnn: bool = False
  288. use_edge_mask_convolutions: bool = True
  289. # use_jit_convolutions: bool = True
  290. # output_format: int = 0 # 0: fp32, 1: fp16
  291. builder_optimization_level: int = 3
  292. max_aux_streams: typing.Optional[int] = None
  293. short_path: typing.Optional[bool] = None # True on Windows by default, False otherwise
  294. custom_env: typing.Dict[str, str] = field(default_factory=lambda: {})
  295. custom_args: typing.List[str] = field(default_factory=lambda: [])
  296. engine_folder: typing.Optional[str] = None
  297. max_tactics: typing.Optional[int] = None
  298. tiling_optimization_level: int = 0
  299. l2_limit_for_tiling: int = -1
  300.  
  301. # internal backend attributes
  302. supports_onnx_serialization: bool = False
  303.  
  304.  
  305. backendT = typing.Union[
  306. Backend.OV_CPU,
  307. Backend.ORT_CPU,
  308. Backend.ORT_CUDA,
  309. Backend.TRT,
  310. Backend.OV_GPU,
  311. Backend.NCNN_VK,
  312. Backend.ORT_DML,
  313. Backend.MIGX,
  314. Backend.OV_NPU,
  315. Backend.ORT_COREML,
  316. Backend.TRT_RTX,
  317. ]
  318.  
  319.  
  320. fallback_backend: typing.Optional[backendT] = None
  321.  
  322.  
  323. @enum.unique
  324. class Waifu2xModel(enum.IntEnum):
  325. anime_style_art = 0
  326. anime_style_art_rgb = 1
  327. photo = 2
  328. upconv_7_anime_style_art_rgb = 3
  329. upconv_7_photo = 4
  330. upresnet10 = 5
  331. cunet = 6
  332. swin_unet_art = 7
  333. swin_unet_photo = 8 # 20230329
  334. swin_unet_photo_v2 = 9 # 20230407
  335. swin_unet_art_scan = 10 # 20230504
  336.  
  337.  
  338. def Waifu2x(
  339. clip: vs.VideoNode,
  340. noise: typing.Literal[-1, 0, 1, 2, 3] = -1,
  341. scale: typing.Literal[1, 2, 4] = 2,
  342. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  343. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  344. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  345. model: Waifu2xModel = Waifu2xModel.cunet,
  346. backend: backendT = Backend.OV_CPU(),
  347. preprocess: bool = True
  348. ) -> vs.VideoNode:
  349.  
  350. func_name = "vsmlrt.Waifu2x"
  351.  
  352. if not isinstance(clip, vs.VideoNode):
  353. raise TypeError(f'{func_name}: "clip" must be a clip!')
  354.  
  355. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  356. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  357.  
  358. if not isinstance(noise, int) or noise not in range(-1, 4):
  359. raise ValueError(f'{func_name}: "noise" must be -1, 0, 1, 2, or 3')
  360.  
  361. if not isinstance(scale, int) or scale not in (1, 2, 4):
  362. raise ValueError(f'{func_name}: "scale" must be 1, 2 or 4')
  363.  
  364. if not isinstance(model, int) or model not in Waifu2xModel.__members__.values():
  365. raise ValueError(f'{func_name}: invalid "model"')
  366.  
  367. if model == 0 and noise == 0:
  368. raise ValueError(
  369. f'{func_name}: "anime_style_art" model'
  370. ' does not support noise reduction level 0'
  371. )
  372.  
  373. if model in range(7) and scale not in (1, 2):
  374. raise ValueError(f'{func_name}: "scale" must be 1 or 2')
  375.  
  376. if model == 0:
  377. if clip.format.color_family != vs.GRAY:
  378. raise ValueError(f'{func_name}: "clip" must be of GRAY color family')
  379. elif clip.format.color_family != vs.RGB:
  380. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  381.  
  382. if overlap is None:
  383. overlap_w = overlap_h = [8, 8, 8, 8, 8, 4, 4, 4, 4, 4, 4][model]
  384. elif isinstance(overlap, int):
  385. overlap_w = overlap_h = overlap
  386. else:
  387. overlap_w, overlap_h = overlap
  388.  
  389. if model == 6:
  390. multiple = 4
  391. else:
  392. multiple = 1
  393.  
  394. width, height = clip.width, clip.height
  395. if preprocess and model in (0, 1, 2):
  396. # emulating cv2.resize(interpolation=cv2.INTER_CUBIC)
  397. clip = core.resize.Bicubic(
  398. clip,
  399. width * 2, height * 2,
  400. filter_param_a=0, filter_param_b=0.75
  401. )
  402.  
  403. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  404. tiles=tiles, tilesize=tilesize,
  405. width=clip.width, height=clip.height,
  406. multiple=multiple,
  407. overlap_w=overlap_w, overlap_h=overlap_h
  408. )
  409.  
  410. if tile_w % multiple != 0 or tile_h % multiple != 0:
  411. raise ValueError(
  412. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  413. )
  414.  
  415. backend = init_backend(
  416. backend=backend,
  417. trt_opt_shapes=(tile_w, tile_h)
  418. )
  419.  
  420. folder_path = os.path.join(
  421. models_path,
  422. "waifu2x",
  423. tuple(Waifu2xModel.__members__)[model]
  424. )
  425.  
  426. if model in (0, 1, 2):
  427. if noise == -1:
  428. model_name = "scale2.0x_model.onnx"
  429. else:
  430. model_name = f"noise{noise}_model.onnx"
  431. elif model in (3, 4, 5):
  432. if noise == -1:
  433. model_name = "scale2.0x_model.onnx"
  434. else:
  435. model_name = f"noise{noise}_scale2.0x_model.onnx"
  436. elif model == 6:
  437. if scale == 1:
  438. scale_name = ""
  439. else:
  440. scale_name = "scale2.0x_"
  441.  
  442. if noise == -1:
  443. model_name = "scale2.0x_model.onnx"
  444. else:
  445. model_name = f"noise{noise}_{scale_name}model.onnx"
  446. elif model == 7:
  447. if scale == 1:
  448. scale_name = ""
  449. elif scale == 2:
  450. scale_name = "scale2x"
  451. elif scale == 4:
  452. scale_name = "scale4x"
  453.  
  454. if noise == -1:
  455. if scale == 1:
  456. raise ValueError("swin_unet model for \"noise == -1\" and \"scale == 1\" does not exist")
  457.  
  458. model_name = f"{scale_name}.onnx"
  459. else:
  460. if scale == 1:
  461. model_name = f"noise{noise}.onnx"
  462. else:
  463. model_name = f"noise{noise}_{scale_name}.onnx"
  464. elif model in (8, 9, 10):
  465. scale_name = "scale4x"
  466. if noise == -1:
  467. model_name = f"{scale_name}.onnx"
  468. else:
  469. model_name = f"noise{noise}_{scale_name}.onnx"
  470. else:
  471. raise ValueError(f"{func_name}: inavlid model {model}")
  472.  
  473. network_path = os.path.join(folder_path, model_name)
  474.  
  475. clip = inference_with_fallback(
  476. clips=[clip], network_path=network_path,
  477. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  478. backend=backend
  479. )
  480.  
  481. if model in range(8) and scale == 1 and clip.width // width == 2:
  482. # emulating cv2.resize(interpolation=cv2.INTER_CUBIC)
  483. # cr: @AkarinVS
  484.  
  485. clip = fmtc_resample(
  486. clip, scale=0.5,
  487. kernel="impulse", impulse=[-0.1875, 1.375, -0.1875],
  488. kovrspl=2
  489. )
  490.  
  491. elif model in (8, 9, 10) and scale != 4:
  492. clip = core.resize.Bicubic(
  493. clip, clip.width * scale // 4, clip.height * scale // 4,
  494. filter_param_a=0, filter_param_b=0.5
  495. )
  496.  
  497. return clip
  498.  
  499.  
  500. @enum.unique
  501. class DPIRModel(enum.IntEnum):
  502. drunet_gray = 0
  503. drunet_color = 1
  504. drunet_deblocking_grayscale = 2
  505. drunet_deblocking_color = 3
  506.  
  507.  
  508. def DPIR(
  509. clip: vs.VideoNode,
  510. strength: typing.Optional[typing.Union[typing.SupportsFloat, vs.VideoNode]],
  511. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  512. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  513. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  514. model: DPIRModel = DPIRModel.drunet_gray,
  515. backend: backendT = Backend.OV_CPU()
  516. ) -> vs.VideoNode:
  517.  
  518. func_name = "vsmlrt.DPIR"
  519.  
  520. if not isinstance(clip, vs.VideoNode):
  521. raise TypeError(f'{func_name}: "clip" must be a clip!')
  522.  
  523. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  524. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  525.  
  526. if not isinstance(model, int) or model not in DPIRModel.__members__.values():
  527. raise ValueError(f'{func_name}: invalid "model"')
  528.  
  529. if model in [0, 2] and clip.format.color_family != vs.GRAY:
  530. raise ValueError(f'{func_name}: "clip" must be of GRAY color family')
  531. elif model in [1, 3] and clip.format.color_family != vs.RGB:
  532. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  533.  
  534. if strength is None:
  535. strength = 5.0
  536.  
  537. gray_format = vs.GRAYS if clip.format.bits_per_sample == 32 else vs.GRAYH
  538.  
  539. if isinstance(strength, vs.VideoNode):
  540. strength = typing.cast(vs.VideoNode, strength)
  541. if strength.format.color_family != vs.GRAY:
  542. raise ValueError(f'{func_name}: "strength" must be of GRAY color family')
  543. if strength.width != clip.width or strength.height != clip.height:
  544. raise ValueError(f'{func_name}: "strength" must be of the same size as "clip"')
  545. if strength.num_frames != clip.num_frames:
  546. raise ValueError(f'{func_name}: "strength" must be of the same length as "clip"')
  547.  
  548. strength = _expr(strength, "x 255 /", format=gray_format)
  549. else:
  550. try:
  551. strength = float(strength)
  552. except TypeError as e:
  553. raise TypeError(f'{func_name}: "strength" must be a float or a clip') from e
  554.  
  555. strength = core.std.BlankClip(clip, format=gray_format, color=strength / 255, keep=True)
  556.  
  557. if overlap is None:
  558. overlap_w = overlap_h = 16
  559. elif isinstance(overlap, int):
  560. overlap_w = overlap_h = overlap
  561. else:
  562. overlap_w, overlap_h = overlap
  563.  
  564. multiple = 8
  565.  
  566. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  567. tiles=tiles, tilesize=tilesize,
  568. width=clip.width, height=clip.height,
  569. multiple=multiple,
  570. overlap_w=overlap_w, overlap_h=overlap_h
  571. )
  572.  
  573. if tile_w % multiple != 0 or tile_h % multiple != 0:
  574. raise ValueError(
  575. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  576. )
  577.  
  578. backend = init_backend(
  579. backend=backend,
  580. trt_opt_shapes=(tile_w, tile_h)
  581. )
  582.  
  583. if (
  584. isinstance(backend, Backend.TRT) and
  585. not backend.force_fp16 and
  586. parse_trt_version(int(core.trt.Version()["tensorrt_version"])) < (11, 0, 0)
  587. ):
  588. backend.custom_args.extend([
  589. "--precisionConstraints=obey",
  590. "--layerPrecisions=Conv_123:fp32"
  591. ])
  592.  
  593. network_path = os.path.join(
  594. models_path,
  595. "dpir",
  596. f"{tuple(DPIRModel.__members__)[model]}.onnx"
  597. )
  598.  
  599. clip = inference_with_fallback(
  600. clips=[clip, strength], network_path=network_path,
  601. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  602. backend=backend
  603. )
  604.  
  605. return clip
  606.  
  607.  
  608. @enum.unique
  609. class RealESRGANModel(enum.IntEnum):
  610. # v2
  611. animevideo_xsx2 = 0
  612. animevideo_xsx4 = 1
  613. # v3
  614. animevideov3 = 2 # 4x
  615. # contributed: janaiV2(2x) https://github.com/the-database/mpv-upscale-2x_animejanai/releases/tag/2.0.0 maintainer: hooke007
  616. animejanaiV2L1 = 5005
  617. animejanaiV2L2 = 5006
  618. animejanaiV2L3 = 5007
  619. # contributed: janaiV3-hd(2x) https://github.com/the-database/mpv-upscale-2x_animejanai/releases/tag/3.0.0 maintainer: hooke007
  620. animejanaiV3_HD_L1 = 5008
  621. animejanaiV3_HD_L2 = 5009
  622. animejanaiV3_HD_L3 = 5010
  623. # contributed=Ani4K-v2 https://github.com/Sirosky/Upscale-Hub/releases/tag/Ani4K-v2
  624. Ani4Kv2_G6i2_Compact = 7000
  625. Ani4Kv2_G6i2_UltraCompact = 7001
  626.  
  627. RealESRGANv2Model = RealESRGANModel
  628.  
  629.  
  630. def RealESRGAN(
  631. clip: vs.VideoNode,
  632. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  633. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  634. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  635. model: RealESRGANv2Model = RealESRGANv2Model.animevideo_xsx2,
  636. backend: backendT = Backend.OV_CPU(),
  637. scale: typing.Optional[float] = None
  638. ) -> vs.VideoNode:
  639.  
  640. func_name = "vsmlrt.RealESRGAN"
  641.  
  642. if not isinstance(clip, vs.VideoNode):
  643. raise TypeError(f'{func_name}: "clip" must be a clip!')
  644.  
  645. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  646. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  647.  
  648. if clip.format.color_family != vs.RGB:
  649. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  650.  
  651. if not isinstance(model, int) or model not in RealESRGANv2Model.__members__.values():
  652. raise ValueError(f'{func_name}: invalid "model"')
  653.  
  654. if overlap is None:
  655. overlap_w = overlap_h = 8
  656. elif isinstance(overlap, int):
  657. overlap_w = overlap_h = overlap
  658. else:
  659. overlap_w, overlap_h = overlap
  660.  
  661. multiple = 1
  662.  
  663. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  664. tiles=tiles, tilesize=tilesize,
  665. width=clip.width, height=clip.height,
  666. multiple=multiple,
  667. overlap_w=overlap_w, overlap_h=overlap_h
  668. )
  669.  
  670. if tile_w % multiple != 0 or tile_h % multiple != 0:
  671. raise ValueError(
  672. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  673. )
  674.  
  675. backend = init_backend(
  676. backend=backend,
  677. trt_opt_shapes=(tile_w, tile_h)
  678. )
  679.  
  680. if model in [0, 1]:
  681. network_path = os.path.join(
  682. models_path,
  683. "RealESRGANv2",
  684. f"RealESRGANv2-{tuple(RealESRGANv2Model.__members__)[model]}.onnx".replace('_', '-')
  685. )
  686. elif model == 2:
  687. network_path = os.path.join(
  688. models_path,
  689. "RealESRGANv2",
  690. "realesr-animevideov3.onnx"
  691. )
  692. elif model in [5005, 5006, 5007, 5008, 5009, 5010, 7000, 7001]:
  693. network_path = os.path.join(
  694. models_path,
  695. "RealESRGANv2",
  696. f"{RealESRGANv2Model(model).name}.onnx".replace('_', '-')
  697. )
  698.  
  699. clip_org = clip
  700. clip = inference_with_fallback(
  701. clips=[clip], network_path=network_path,
  702. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  703. backend=backend
  704. )
  705.  
  706. if scale is not None:
  707. scale_h = clip.width // clip_org.width
  708. scale_v = clip.height // clip_org.height
  709.  
  710. assert scale_h == scale_v
  711.  
  712. if scale != scale_h:
  713. rescale = scale / scale_h
  714.  
  715. if rescale > 1:
  716. clip = core.resize.Lanczos(clip, int(clip_org.width * scale), int(clip_org.height * scale), filter_param_a=4)
  717. else:
  718. clip = fmtc_resample(clip, scale=rescale, kernel="lanczos", taps=4, fh=1/rescale, fv=1/rescale)
  719.  
  720. return clip
  721.  
  722. RealESRGANv2 = RealESRGAN
  723.  
  724.  
  725. def CUGAN(
  726. clip: vs.VideoNode,
  727. noise: typing.Literal[-1, 0, 1, 2, 3] = -1,
  728. scale: typing.Literal[2, 3, 4] = 2,
  729. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  730. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  731. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  732. backend: backendT = Backend.OV_CPU(),
  733. alpha: float = 1.0,
  734. version: typing.Literal[1, 2] = 1, # 1: legacy, 2: pro
  735. conformance: bool = True # currently specifies dynamic range compression for cugan-pro
  736. ) -> vs.VideoNode:
  737. """
  738. denoising strength: 0 < -1 < 1 < 2 < 3
  739.  
  740. version: (1 or 2)
  741. 1 -> legacy,
  742. 2 -> pro (only models for "noise" in [-1, 0, 3] and "scale" in [2, 3] are published currently)
  743. """
  744.  
  745. func_name = "vsmlrt.CUGAN"
  746.  
  747. if not isinstance(clip, vs.VideoNode):
  748. raise TypeError(f'{func_name}: "clip" must be a clip!')
  749.  
  750. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  751. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  752.  
  753. if not isinstance(noise, int) or noise not in range(-1, 4):
  754. raise ValueError(f'{func_name}: "noise" must be -1, 0, 1, 2, or 3')
  755.  
  756. if not isinstance(scale, int) or scale not in (2, 3, 4):
  757. raise ValueError(f'{func_name}: "scale" must be 2, 3 or 4')
  758.  
  759. if scale != 2 and noise in [1, 2]:
  760. raise ValueError(
  761. f'{func_name}: "scale={scale}" model'
  762. f' does not support noise reduction level {noise}'
  763. )
  764.  
  765. if clip.format.color_family != vs.RGB:
  766. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  767.  
  768. if overlap is None:
  769. overlap_w = overlap_h = 4
  770. elif isinstance(overlap, int):
  771. overlap_w = overlap_h = overlap
  772. else:
  773. overlap_w, overlap_h = overlap
  774.  
  775. multiple = 2
  776.  
  777. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  778. tiles=tiles, tilesize=tilesize,
  779. width=clip.width, height=clip.height,
  780. multiple=multiple,
  781. overlap_w=overlap_w, overlap_h=overlap_h
  782. )
  783.  
  784. if tile_w % multiple != 0 or tile_h % multiple != 0:
  785. raise ValueError(
  786. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  787. )
  788.  
  789. backend = init_backend(
  790. backend=backend,
  791. trt_opt_shapes=(tile_w, tile_h)
  792. )
  793.  
  794. folder_path = os.path.join(models_path, "cugan")
  795.  
  796. if version == 1:
  797. if noise == -1:
  798. model_name = f"up{scale}x-latest-no-denoise.onnx"
  799. elif noise == 0:
  800. model_name = f"up{scale}x-latest-conservative.onnx"
  801. else:
  802. model_name = f"up{scale}x-latest-denoise{noise}x.onnx"
  803. elif version == 2:
  804. if noise == -1:
  805. model_name = f"pro-no-denoise3x-up{scale}x.onnx"
  806. elif noise == 0:
  807. model_name = f"pro-conservative-up{scale}x.onnx"
  808. else:
  809. model_name = f"pro-denoise{noise}x-up{scale}x.onnx"
  810. else:
  811. raise ValueError(f'{func_name}: unknown version ({version}), must be 1 (legacy) or 2 (pro)')
  812.  
  813. network_path = os.path.join(folder_path, model_name)
  814.  
  815. # https://github.com/bilibili/ailab/blob/978f3be762183d7fa79525f29a43e65afb995f6b/Real-CUGAN/upcunet_v3.py#L207
  816. # mutates network_path
  817. if alpha != 1.0:
  818. alpha = float(alpha)
  819.  
  820. import numpy as np
  821. import onnx
  822. from onnx import numpy_helper
  823.  
  824. model = onnx.load(network_path)
  825.  
  826. for idx, node in reversed(list(enumerate(model.graph.node))):
  827. if node.op_type == "ConvTranspose":
  828. break
  829.  
  830. upstream_name = node.input[0]
  831. downstream_name = node.input[0] + "_mul"
  832. node.input[0] = downstream_name
  833.  
  834. alpha_array = np.array(alpha, dtype=np.float32)
  835. alpha_tensor = numpy_helper.from_array(alpha_array)
  836. alpha_constant = onnx.helper.make_node(
  837. "Constant",
  838. inputs=[],
  839. outputs=["alpha"],
  840. value=alpha_tensor
  841. )
  842. model.graph.node.insert(idx, alpha_constant)
  843.  
  844. mul_node = onnx.helper.make_node(
  845. "Mul",
  846. inputs=[upstream_name, "alpha"],
  847. outputs=[downstream_name]
  848. )
  849. model.graph.node.insert(idx+1, mul_node)
  850.  
  851. if backend.supports_onnx_serialization:
  852. if conformance and version == 2:
  853. clip = _expr(clip, "x 0.7 * 0.15 +")
  854.  
  855. clip = inference_with_fallback(
  856. clips=[clip], network_path=model.SerializeToString(),
  857. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  858. backend=backend, path_is_serialization=True
  859. )
  860.  
  861. if conformance and version == 2:
  862. clip = _expr(clip, "x 0.15 - 0.7 /")
  863.  
  864. return clip
  865.  
  866. network_path = f"{network_path}_alpha{alpha!r}.onnx"
  867. onnx.save(model, network_path)
  868.  
  869. # https://github.com/bilibili/ailab/blob/e102bef22384c629f82552dbec3d6b5bab125639/Real-CUGAN/upcunet_v3.py#L1275-L1276
  870. if conformance and version == 2:
  871. clip = _expr(clip, "x 0.7 * 0.15 +")
  872.  
  873. clip = inference_with_fallback(
  874. clips=[clip], network_path=network_path,
  875. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  876. backend=backend
  877. )
  878.  
  879. # https://github.com/bilibili/ailab/blob/e102bef22384c629f82552dbec3d6b5bab125639/Real-CUGAN/upcunet_v3.py#L269
  880. if conformance and version == 2:
  881. clip = _expr(clip, "x 0.15 - 0.7 /")
  882.  
  883. return clip
  884.  
  885.  
  886. def get_rife_input(clip: vs.VideoNode) -> typing.List[vs.VideoNode]:
  887. assert clip.format.sample_type == vs.FLOAT
  888. gray_format = vs.GRAYS if clip.format.bits_per_sample == 32 else vs.GRAYH
  889.  
  890.  
  891. if (hasattr(core, 'akarin') and
  892. b"width" in core.akarin.Version()["expr_features"] and
  893. b"height" in core.akarin.Version()["expr_features"]
  894. ):
  895. if b"fp16" in core.akarin.Version()["expr_features"]:
  896. empty = clip.std.BlankClip(format=gray_format, length=1)
  897. else:
  898. empty = clip.std.BlankClip(format=vs.GRAYS, length=1)
  899.  
  900. horizontal = bits_as(core.akarin.Expr(empty, 'X 2 * width 1 - / 1 -'), clip)
  901. vertical = bits_as(core.akarin.Expr(empty, 'Y 2 * height 1 - / 1 -'), clip)
  902. else:
  903. empty = clip.std.BlankClip(format=vs.GRAYS, length=1)
  904.  
  905. from functools import partial
  906.  
  907. def meshgrid_core(n: int, f: vs.VideoFrame, horizontal: bool) -> vs.VideoFrame:
  908. fout = f.copy()
  909.  
  910. is_api4 = hasattr(vs, "__api_version__") and vs.__api_version__.api_major == 4
  911. if is_api4:
  912. mem_view = fout[0]
  913. else:
  914. mem_view = fout.get_write_array(0)
  915.  
  916. height, width = mem_view.shape
  917.  
  918. if horizontal:
  919. for i in range(height):
  920. for j in range(width):
  921. mem_view[i, j] = 2 * j / (width - 1) - 1
  922. else:
  923. for i in range(height):
  924. for j in range(width):
  925. mem_view[i, j] = 2 * i / (height - 1) - 1
  926.  
  927. return fout
  928.  
  929. horizontal = bits_as(core.std.ModifyFrame(empty, empty, partial(meshgrid_core, horizontal=True)), clip)
  930. vertical = bits_as(core.std.ModifyFrame(empty, empty, partial(meshgrid_core, horizontal=False)), clip)
  931.  
  932. horizontal = horizontal.std.Loop(clip.num_frames)
  933. vertical = vertical.std.Loop(clip.num_frames)
  934.  
  935. multiplier_h = clip.std.BlankClip(format=gray_format, color=2/(clip.width-1), keep=True)
  936.  
  937. multiplier_w = clip.std.BlankClip(format=gray_format, color=2/(clip.height-1), keep=True)
  938.  
  939. return [horizontal, vertical, multiplier_h, multiplier_w]
  940.  
  941.  
  942. @enum.unique
  943. class RIFEModel(enum.IntEnum):
  944. """
  945. Starting from RIFE v4.12 lite, this interface does not provide forward compatiblity in enum values.
  946. """
  947.  
  948. v4_0 = 40
  949. v4_2 = 42
  950. v4_3 = 43
  951. v4_4 = 44
  952. v4_5 = 45
  953. v4_6 = 46
  954. v4_7 = 47
  955. v4_8 = 48
  956. v4_9 = 49
  957. v4_10 = 410
  958. v4_11 = 411
  959. v4_12 = 412
  960. v4_12_lite = 4121
  961. v4_13 = 413
  962. v4_13_lite = 4131
  963. v4_14 = 414
  964. v4_14_lite = 4141
  965. v4_15 = 415
  966. v4_15_lite = 4151
  967. v4_16_lite = 4161
  968. v4_17 = 417
  969. v4_17_lite = 4171
  970. v4_18 = 418
  971. v4_19 = 419
  972. v4_20 = 420
  973. v4_21 = 421
  974. v4_22 = 422
  975. v4_22_lite = 4221
  976. v4_23 = 423
  977. v4_24 = 424
  978. v4_25 = 425
  979. v4_25_lite = 4251
  980. v4_25_heavy = 4252
  981. v4_26 = 426
  982. v4_26_heavy = 4262
  983.  
  984.  
  985. def RIFEMerge(
  986. clipa: vs.VideoNode,
  987. clipb: vs.VideoNode,
  988. mask: vs.VideoNode,
  989. scale: float = 1.0,
  990. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  991. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  992. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  993. model: RIFEModel = RIFEModel.v4_4,
  994. backend: backendT = Backend.OV_CPU(),
  995. ensemble: bool = False,
  996. _implementation: typing.Optional[typing.Literal[1, 2]] = None
  997. ) -> vs.VideoNode:
  998. """ temporal MaskedMerge-like interface for the RIFE model
  999.  
  1000. Its semantics is similar to core.std.MaskedMerge(clipa, clipb, mask, first_plane=True),
  1001. except that it merges the two clips in the time domain and you specify the "mask" based
  1002. on the time point of the resulting clip (range (0,1)) between the two clips.
  1003. """
  1004.  
  1005. func_name = "vsmlrt.RIFEMerge"
  1006.  
  1007. for clip in (clipa, clipb, mask):
  1008. if not isinstance(clip, vs.VideoNode):
  1009. raise TypeError(f'{func_name}: clip must be a clip!')
  1010.  
  1011. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  1012. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  1013.  
  1014. for clip in (clipa, clipb):
  1015. if clip.format.color_family != vs.RGB:
  1016. raise ValueError(f'{func_name}: "clipa" / "clipb" must be of RGB color family')
  1017.  
  1018. if clip.width != mask.width or clip.height != mask.height:
  1019. raise ValueError(f'{func_name}: video dimensions mismatch')
  1020.  
  1021. if clip.num_frames != mask.num_frames:
  1022. raise ValueError(f'{func_name}: number of frames mismatch')
  1023.  
  1024. if mask.format.color_family != vs.GRAY:
  1025. raise ValueError(f'{func_name}: "mask" must be of GRAY color family')
  1026.  
  1027. if tiles is not None or tilesize is not None or overlap is not None:
  1028. raise ValueError(f'{func_name}: tiling is not supported')
  1029.  
  1030. if overlap is None:
  1031. overlap_w = overlap_h = 0
  1032. elif isinstance(overlap, int):
  1033. overlap_w = overlap_h = overlap
  1034. else:
  1035. overlap_w, overlap_h = overlap
  1036.  
  1037. model_major = int(str(int(model))[0])
  1038. model_minor = int(str(int(model))[1:3])
  1039. if len(str(int(model))) >= 4:
  1040. if str(int(model))[-1] == '1':
  1041. rife_type = "_lite"
  1042. elif str(int(model))[-1] == '2':
  1043. rife_type = "_heavy"
  1044. else:
  1045. rife_type = ""
  1046.  
  1047. if (model_major, model_minor) >= (4, 26):
  1048. tilesize_requirement = 64
  1049. elif (model_major, model_minor, rife_type) == (4, 25, "_lite"):
  1050. tilesize_requirement = 128
  1051. elif (model_major, model_minor, rife_type) == (4, 25, "_heavy"):
  1052. tilesize_requirement = 64
  1053. elif (model_major, model_minor, rife_type) == (4, 26, "_heavy"):
  1054. tilesize_requirement = 64
  1055. else:
  1056. tilesize_requirement = 32
  1057.  
  1058. multiple_frac = tilesize_requirement / Fraction(scale)
  1059. if multiple_frac.denominator != 1:
  1060. raise ValueError(f'{func_name}: ({tilesize_requirement} / Fraction(scale)) must be an integer')
  1061. multiple = int(multiple_frac.numerator)
  1062. scale = float(Fraction(scale))
  1063.  
  1064. if model_major == 4 and (model_minor in (21, 22, 23) or model_minor >= 25) and ensemble:
  1065. raise ValueError(f'{func_name}: ensemble is not supported')
  1066.  
  1067. version = f"v{model_major}.{model_minor}{rife_type}{'_ensemble' if ensemble else ''}"
  1068.  
  1069. if (model_major, model_minor) >= (4, 7) and scale != 1.0:
  1070. raise ValueError("not supported")
  1071.  
  1072. network_path = os.path.join(
  1073. models_path,
  1074. "rife_v2",
  1075. f"rife_{version}.onnx"
  1076. )
  1077. if _implementation == 2 and os.path.exists(network_path) and scale == 1.0:
  1078. implementation_version = 2
  1079. multiple = 1 # v2 implements internal padding
  1080. clips = [clipa, clipb, mask]
  1081. else:
  1082. implementation_version = 1
  1083.  
  1084. network_path = os.path.join(
  1085. models_path,
  1086. "rife",
  1087. f"rife_{version}.onnx"
  1088. )
  1089.  
  1090. clips = [clipa, clipb, mask, *get_rife_input(clipa)]
  1091.  
  1092. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  1093. tiles=tiles, tilesize=tilesize,
  1094. width=clip.width, height=clip.height,
  1095. multiple=multiple,
  1096. overlap_w=overlap_w, overlap_h=overlap_h
  1097. )
  1098.  
  1099. if tile_w % multiple != 0 or tile_h % multiple != 0:
  1100. raise ValueError(
  1101. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  1102. )
  1103.  
  1104. backend = init_backend(
  1105. backend=backend,
  1106. trt_opt_shapes=(tile_w, tile_h)
  1107. )
  1108.  
  1109. if implementation_version == 2:
  1110. if isinstance(backend, Backend.TRT):
  1111. # https://github.com/AmusementClub/vs-mlrt/issues/66#issuecomment-1791986979
  1112. if (4, 0) <= (model_major, model_minor):
  1113. if backend.force_fp16:
  1114. backend.force_fp16 = False
  1115. backend.fp16 = True
  1116.  
  1117. if parse_trt_version(int(core.trt.Version()["tensorrt_version"])) < (11, 0, 0):
  1118. backend.custom_args.extend([
  1119. "--precisionConstraints=obey",
  1120. "--layerPrecisions=" + (
  1121. "/Cast_2:fp32,/Cast_3:fp32,/Cast_5:fp32,/Cast_7:fp32,"
  1122. "/Reciprocal:fp32,/Reciprocal_1:fp32,"
  1123. "/Mul:fp32,/Mul_1:fp32,/Mul_8:fp32,/Mul_10:fp32,"
  1124. "/Sub_5:fp32,/Sub_6:fp32,"
  1125. # generated by TensorRT's onnx parser
  1126. "ONNXTRT_Broadcast_236:fp32,ONNXTRT_Broadcast_238:fp32,"
  1127. "ONNXTRT_Broadcast_273:fp32,ONNXTRT_Broadcast_275:fp32,"
  1128. # TensorRT 9.0 or later
  1129. "ONNXTRT_Broadcast_*:fp32"
  1130. )
  1131. ])
  1132.  
  1133. if scale == 1.0:
  1134. return inference_with_fallback(
  1135. clips=clips, network_path=network_path,
  1136. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1137. backend=backend
  1138. )
  1139. elif ensemble or implementation_version != 1:
  1140. raise ValueError(f'{func_name}: currently not supported')
  1141. else:
  1142. import onnx
  1143. from onnx.numpy_helper import from_array, to_array
  1144.  
  1145. onnx_model = onnx.load(network_path)
  1146.  
  1147. resize_counter = 0
  1148. for i in range(len(onnx_model.graph.node)):
  1149. node = onnx_model.graph.node[i]
  1150. if len(node.output) == 1 and node.op_type == "Constant" and node.output[0].startswith("onnx::Resize"):
  1151. resize_counter += 1
  1152.  
  1153. array = to_array(node.attribute[0].t).copy()
  1154. if resize_counter % 3 == 2:
  1155. array[2:4] /= scale
  1156. else:
  1157. array[2:4] *= scale
  1158. onnx_model.graph.node[i].attribute[0].t.raw_data = from_array(array).raw_data
  1159.  
  1160. if resize_counter != 11:
  1161. raise ValueError("invalid rife model")
  1162.  
  1163. multiplier_counter = 0
  1164. for i in range(len(onnx_model.graph.node)):
  1165. node = onnx_model.graph.node[i]
  1166. if len(node.output) == 1 and node.op_type == "Constant" and node.output[0].startswith("onnx::Mul"):
  1167. multiplier_counter += 1
  1168.  
  1169. array = to_array(node.attribute[0].t).copy()
  1170. if multiplier_counter % 2 == 1:
  1171. array /= scale
  1172. else:
  1173. array *= scale
  1174. onnx_model.graph.node[i].attribute[0].t.raw_data = from_array(array).raw_data
  1175.  
  1176. if multiplier_counter != 7:
  1177. raise ValueError("invalid rife model")
  1178.  
  1179. if backend.supports_onnx_serialization:
  1180. return inference_with_fallback(
  1181. clips=clips, network_path=onnx_model.SerializeToString(),
  1182. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1183. backend=backend, path_is_serialization=True
  1184. )
  1185. else:
  1186. network_path = f"{network_path}_scale{scale!r}.onnx"
  1187. onnx.save(onnx_model, network_path)
  1188.  
  1189. return inference_with_fallback(
  1190. clips=clips, network_path=network_path,
  1191. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1192. backend=backend
  1193. )
  1194.  
  1195.  
  1196. def RIFE(
  1197. clip: vs.VideoNode,
  1198. multi: typing.Union[int, Fraction] = 2,
  1199. scale: float = 1.0,
  1200. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1201. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1202. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1203. model: RIFEModel = RIFEModel.v4_4,
  1204. backend: backendT = Backend.OV_CPU(),
  1205. ensemble: bool = False,
  1206. video_player: bool = False,
  1207. _implementation: typing.Optional[typing.Literal[1, 2]] = None
  1208. ) -> vs.VideoNode:
  1209. """ RIFE: Real-Time Intermediate Flow Estimation for Video Frame Interpolation
  1210.  
  1211. multi, scale is based on vs-rife.
  1212.  
  1213. For the best results, you need to perform scene detection on the input clip
  1214. (e.g. misc.SCDetect, mv.SCDetection) before passing it to RIFE.
  1215. Also note that the quality of result is strongly dependent on high quality
  1216. scene detection and you might need to tweak the scene detection parameters
  1217. and/or filter to achieve the best quality.
  1218.  
  1219. Args:
  1220. multi: Multiple of the frame counts, can be a fractions.Fraction.
  1221. Default: 2.
  1222.  
  1223. scale: Controls the process resolution for optical flow model.
  1224. 32 / fractions.Fraction(scale) must be an integer.
  1225. scale=0.5 is recommended for 4K video.
  1226.  
  1227. _implementation: (None, 1 or 2, experimental and maybe removed in the future)
  1228. Switch between different onnx implementation.
  1229. Implmementation will be selected based on internal heuristic if it is None.
  1230. """
  1231.  
  1232. func_name = "vsmlrt.RIFE"
  1233.  
  1234. if not isinstance(clip, vs.VideoNode):
  1235. raise TypeError(f'{func_name}: "clip" must be a clip!')
  1236.  
  1237. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  1238. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  1239.  
  1240. if clip.format.color_family != vs.RGB:
  1241. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  1242.  
  1243. if not isinstance(multi, (int, Fraction)):
  1244. raise TypeError(f'{func_name}: "multi" must be an integer or a fractions.Fraction!')
  1245.  
  1246. if tiles is not None or tilesize is not None or overlap is not None:
  1247. raise ValueError(f'{func_name}: tiling is not supported')
  1248.  
  1249. gray_format = vs.GRAYS if clip.format.bits_per_sample == 32 else vs.GRAYH
  1250.  
  1251. if int(multi) == multi:
  1252. multi = int(multi)
  1253.  
  1254. if multi < 2:
  1255. raise ValueError(f'{func_name}: RIFE: multi must be at least 2')
  1256.  
  1257. initial = core.std.Interleave([clip] * (multi - 1))
  1258.  
  1259. terminal = clip.std.DuplicateFrames(frames=clip.num_frames - 1).std.Trim(first=1)
  1260. terminal = core.std.Interleave([terminal] * (multi - 1))
  1261.  
  1262. timepoint = core.std.Interleave([
  1263. clip.std.BlankClip(format=gray_format, color=i/multi, length=1)
  1264. for i in range(1, multi)
  1265. ]).std.Loop(clip.num_frames)
  1266.  
  1267. output0 = RIFEMerge(
  1268. clipa=initial, clipb=terminal, mask=timepoint,
  1269. scale=scale, tiles=tiles, tilesize=tilesize, overlap=overlap,
  1270. model=model, backend=backend, ensemble=ensemble,
  1271. _implementation=_implementation
  1272. )
  1273.  
  1274. clip = bits_as(clip, output0)
  1275. initial = core.std.Interleave([clip] * (multi - 1))
  1276.  
  1277. if hasattr(core, 'akarin') and hasattr(core.akarin, 'Select'):
  1278. output = core.akarin.Select([output0, initial], initial, 'x._SceneChangeNext 1 0 ?')
  1279. else:
  1280. def handler(n: int, f: vs.VideoFrame) -> vs.VideoNode:
  1281. if f.props.get('_SceneChangeNext'):
  1282. return initial
  1283. return output0
  1284. output = core.std.FrameEval(output0, handler, initial)
  1285.  
  1286. if multi == 2:
  1287. res = core.std.Interleave([clip, output])
  1288. else:
  1289. res = core.std.Interleave([
  1290. clip,
  1291. *(output.std.SelectEvery(cycle=multi-1, offsets=i) for i in range(multi - 1))
  1292. ])
  1293.  
  1294. if clip.fps_num != 0 and clip.fps_den != 0:
  1295. return res.std.AssumeFPS(fpsnum = clip.fps_num * multi, fpsden = clip.fps_den)
  1296. else:
  1297. return res
  1298. else:
  1299. if clip.fps_num == 0 or clip.fps_den == 0:
  1300. src_fps = Fraction(1)
  1301. else:
  1302. src_fps = clip.fps
  1303.  
  1304. dst_fps = src_fps * multi
  1305. src_frames = clip.num_frames
  1306. dst_frames = min(int(src_frames * multi), 2 ** 31 - 1)
  1307.  
  1308. duration_rel = src_fps / dst_fps
  1309. dst_duration = duration_rel.numerator
  1310. src_duration = duration_rel.denominator
  1311.  
  1312. # https://github.com/AmusementClub/vs-mlrt/issues/59#issuecomment-1842649342
  1313. if video_player:
  1314. temp = core.std.BlankClip(clip, length=dst_frames, keep=True)
  1315.  
  1316. def left_func(n: int) -> vs.VideoNode:
  1317. return clip[dst_duration * n // src_duration]
  1318. left_clip = core.std.FrameEval(temp, left_func)
  1319.  
  1320. def right_func(n: int) -> vs.VideoNode:
  1321. # no out of range access because of function filter_sc
  1322. return clip[dst_duration * n // src_duration + 1]
  1323. right_clip = core.std.FrameEval(temp, right_func)
  1324.  
  1325. temp_gray = core.std.BlankClip(temp, format=gray_format, keep=True)
  1326. def timepoint_func(n: int) -> vs.VideoNode:
  1327. current_time = dst_duration * n
  1328. left_index = current_time // src_duration
  1329. left_time = src_duration * left_index
  1330. tp = (current_time - left_time) / src_duration
  1331. return temp_gray.std.BlankClip(color=tp, keep=True)
  1332. tp_clip = core.std.FrameEval(temp_gray, timepoint_func)
  1333.  
  1334. output0 = RIFEMerge(
  1335. clipa=left_clip, clipb=right_clip, mask=tp_clip,
  1336. scale=scale, tiles=tiles, tilesize=tilesize, overlap=overlap,
  1337. model=model, backend=backend, ensemble=ensemble,
  1338. _implementation=_implementation
  1339. )
  1340.  
  1341. left0 = bits_as(left_clip, output0)
  1342.  
  1343. def filter_sc(n: int, f: vs.VideoFrame) -> vs.VideoNode:
  1344. current_time = dst_duration * n
  1345. left_index = current_time // src_duration
  1346. if (
  1347. current_time % src_duration == 0 or
  1348. left_index + 1 >= src_frames or
  1349. f.props.get("_SceneChangeNext", False)
  1350. ):
  1351. return left0
  1352. else:
  1353. return output0
  1354.  
  1355. res = core.std.FrameEval(output0, filter_sc, left0)
  1356. else:
  1357. if not hasattr(core, 'akarin') or \
  1358. not hasattr(core.akarin, 'PropExpr') or \
  1359. not hasattr(core.akarin, 'PickFrames'):
  1360. raise RuntimeError(
  1361. 'fractional multi requires plugin akarin '
  1362. '(https://github.com/AkarinVS/vapoursynth-plugin/releases)'
  1363. ', version v0.96g or later.')
  1364.  
  1365. left_indices = []
  1366. right_indices = []
  1367. timepoints = []
  1368. output_indices = []
  1369.  
  1370. for i in range(dst_frames):
  1371. current_time = dst_duration * i
  1372. if current_time % src_duration == 0:
  1373. output_indices.append(current_time // src_duration)
  1374. else:
  1375. left_index = current_time // src_duration
  1376. if left_index + 1 >= src_frames:
  1377. # approximate last frame with last frame of source
  1378. output_indices.append(src_frames - 1)
  1379. break
  1380. output_indices.append(src_frames + len(timepoints))
  1381. left_indices.append(left_index)
  1382. right_indices.append(left_index + 1)
  1383. left_time = src_duration * left_index
  1384. tp = (current_time - left_time) / src_duration
  1385. timepoints.append(tp)
  1386.  
  1387. left_clip = core.akarin.PickFrames(clip, left_indices)
  1388. right_clip = core.akarin.PickFrames(clip, right_indices)
  1389. tp_clip = core.std.BlankClip(clip, format=gray_format, length=len(timepoints))
  1390. tp_clip = tp_clip.akarin.PropExpr(lambda: dict(_tp=timepoints)).akarin.Expr('x._tp')
  1391.  
  1392. output0 = RIFEMerge(
  1393. clipa=left_clip, clipb=right_clip, mask=tp_clip,
  1394. scale=scale, tiles=tiles, tilesize=tilesize, overlap=overlap,
  1395. model=model, backend=backend, ensemble=ensemble,
  1396. _implementation=_implementation
  1397. )
  1398.  
  1399. clip0 = bits_as(clip, output0)
  1400. left0 = bits_as(left_clip, output0)
  1401. output = core.akarin.Select([output0, left0], left0, 'x._SceneChangeNext 1 0 ?')
  1402. res = core.akarin.PickFrames(clip0 + output, output_indices)
  1403.  
  1404. if clip.fps_num != 0 and clip.fps_den != 0:
  1405. return res.std.AssumeFPS(fpsnum = dst_fps.numerator, fpsden = dst_fps.denominator)
  1406. else:
  1407. return res
  1408.  
  1409.  
  1410. @enum.unique
  1411. class SAFAModel(enum.IntEnum):
  1412. v0_1 = 1
  1413. v0_2 = 2
  1414. v0_3 = 3
  1415. v0_4 = 4
  1416. v0_5 = 5
  1417.  
  1418.  
  1419. @enum.unique
  1420. class SAFAAdaptiveMode(enum.IntEnum):
  1421. non_adaptive = 0 # non-adaptive
  1422. adaptive1x = 1 # use adaptive path only at 1x scale
  1423. adaptive = 2 # use adaptive path at 1x, 1/2x and 1/4x scales, proposed algorithm
  1424.  
  1425.  
  1426. def SAFA(
  1427. clip: vs.VideoNode,
  1428. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1429. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1430. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1431. model: SAFAModel = SAFAModel.v0_1,
  1432. adaptive: SAFAAdaptiveMode = SAFAAdaptiveMode.non_adaptive,
  1433. backend: backendT = Backend.OV_CPU(),
  1434. ) -> vs.VideoNode:
  1435. """ SAFA: Scale-Adaptive Feature Aggregation for Efficient Space-Time Video Super-Resolution
  1436. """
  1437.  
  1438. func_name = "vsmlrt.SAFA"
  1439.  
  1440. if not isinstance(clip, vs.VideoNode):
  1441. raise TypeError(f'{func_name}: "clip" must be a clip!')
  1442.  
  1443. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  1444. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  1445.  
  1446. if clip.format.color_family != vs.RGB:
  1447. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  1448.  
  1449. if clip.num_frames == 1:
  1450. raise ValueError(f'{func_name}: "clip" too short!')
  1451.  
  1452. if overlap is None:
  1453. overlap_w = overlap_h = 16
  1454. elif isinstance(overlap, int):
  1455. overlap_w = overlap_h = overlap
  1456. else:
  1457. overlap_w, overlap_h = overlap
  1458.  
  1459. # unknown crash
  1460. if model <= 2:
  1461. multiple = 8
  1462. else:
  1463. multiple = 16
  1464.  
  1465. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  1466. tiles=tiles, tilesize=tilesize,
  1467. width=clip.width, height=clip.height,
  1468. multiple=multiple,
  1469. overlap_w=overlap_w, overlap_h=overlap_h
  1470. )
  1471.  
  1472. if tile_w % multiple != 0 or tile_h % multiple != 0:
  1473. raise ValueError(
  1474. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  1475. )
  1476.  
  1477. backend = init_backend(
  1478. backend=backend,
  1479. trt_opt_shapes=(tile_w, tile_h)
  1480. )
  1481.  
  1482. _adaptive = SAFAAdaptiveMode(adaptive)
  1483.  
  1484. if isinstance(backend, Backend.TRT):
  1485. if backend.force_fp16:
  1486. backend.force_fp16 = False
  1487. backend.fp16 = True
  1488.  
  1489. cast1, cast2 = [(218, 255), (266, 303), (254, 291)][_adaptive]
  1490.  
  1491. if parse_trt_version(int(core.trt.Version()["tensorrt_version"])) < (11, 0, 0):
  1492. backend.custom_args.extend([
  1493. "--precisionConstraints=obey",
  1494. "--layerPrecisions=" + (
  1495. "/Div_2:fp32,/Div_3:fp32,/Div_4:fp32,/Div_5:fp32,/Div_6:fp32,/Div_7:fp32,"
  1496. "/Cast_7:fp32,/Cast_8:fp32,/Cast_10:fp32,/Cast_11:fp32,"
  1497. f"Cast_{cast1}:fp32,Cast_{cast2}:fp32,"
  1498. "/Sub_3:fp32,/Sub_4:fp32"
  1499. )
  1500. ])
  1501.  
  1502. model_version = SAFAModel(model).name.replace('_', '.')
  1503. adaptive_string = _adaptive.name
  1504.  
  1505. network_path = os.path.join(
  1506. models_path,
  1507. "safa",
  1508. f"safa_{model_version}_{adaptive_string}.onnx"
  1509. )
  1510.  
  1511. clip_org = clip
  1512.  
  1513. clips = [clip[::2], clip[1::2]]
  1514. if clips[0].num_frames != clips[1].num_frames:
  1515. clips[1] = core.std.Splice([clips[1], clip[-1]])
  1516.  
  1517. clip2x = inference_with_fallback(
  1518. clips=clips, network_path=network_path,
  1519. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1520. backend=backend
  1521. )
  1522.  
  1523. up = core.std.Crop(clip2x, bottom=clip2x.height // 2)
  1524. down = core.std.Crop(clip2x, top=clip2x.height // 2)
  1525. clip = core.std.Interleave([up, down])
  1526.  
  1527. if clip.num_frames != clip_org.num_frames:
  1528. clip = clip[:-1]
  1529.  
  1530. return clip
  1531.  
  1532.  
  1533. @enum.unique
  1534. class SCUNetModel(enum.IntEnum):
  1535. scunet_color_15 = 0
  1536. scunet_color_25 = 1
  1537. scunet_color_50 = 2
  1538. scunet_color_real_psnr = 3
  1539. scunet_color_real_gan = 4
  1540. scunet_gray_15 = 5
  1541. scunet_gray_25 = 6
  1542. scunet_gray_50 = 7
  1543.  
  1544.  
  1545. def SCUNet(
  1546. clip: vs.VideoNode,
  1547. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1548. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1549. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1550. model: SCUNetModel = SCUNetModel.scunet_color_real_psnr,
  1551. backend: backendT = Backend.OV_CPU()
  1552. ) -> vs.VideoNode:
  1553. """ Practical Blind Denoising via Swin-Conv-UNet and Data Synthesis
  1554.  
  1555. Unlike vs-scunet v1.0.0, the default model is set to scunet_color_real_psnr due to the color shift.
  1556. """
  1557.  
  1558. func_name = "vsmlrt.SCUNet"
  1559.  
  1560. if not isinstance(clip, vs.VideoNode):
  1561. raise TypeError(f'{func_name}: "clip" must be a clip!')
  1562.  
  1563. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  1564. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  1565.  
  1566. if not isinstance(model, int) or model not in SCUNetModel.__members__.values():
  1567. raise ValueError(f'{func_name}: invalid "model"')
  1568.  
  1569. if model in range(5) and clip.format.color_family != vs.RGB:
  1570. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  1571. elif model in range(5, 8) and clip.format.color_family != vs.GRAY:
  1572. raise ValueError(f'{func_name}: "clip" must be of GRAY color family')
  1573.  
  1574. if overlap is None:
  1575. overlap_w = overlap_h = 64
  1576. elif isinstance(overlap, int):
  1577. overlap_w = overlap_h = overlap
  1578. else:
  1579. overlap_w, overlap_h = overlap
  1580.  
  1581. multiple = 1
  1582.  
  1583. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  1584. tiles=tiles, tilesize=tilesize,
  1585. width=clip.width, height=clip.height,
  1586. multiple=multiple,
  1587. overlap_w=overlap_w, overlap_h=overlap_h
  1588. )
  1589.  
  1590. if tile_w % multiple != 0 or tile_h % multiple != 0:
  1591. raise ValueError(
  1592. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  1593. )
  1594.  
  1595. backend = init_backend(
  1596. backend=backend,
  1597. trt_opt_shapes=(tile_w, tile_h)
  1598. )
  1599.  
  1600. network_path = os.path.join(
  1601. models_path,
  1602. "scunet",
  1603. f"{tuple(SCUNetModel.__members__)[model]}.onnx"
  1604. )
  1605.  
  1606. clip = inference_with_fallback(
  1607. clips=[clip], network_path=network_path,
  1608. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1609. backend=backend
  1610. )
  1611.  
  1612. return clip
  1613.  
  1614.  
  1615. @enum.unique
  1616. class SwinIRModel(enum.IntEnum):
  1617. lightweightSR_DIV2K_s64w8_SwinIR_S_x2 = 0
  1618. lightweightSR_DIV2K_s64w8_SwinIR_S_x3 = 1
  1619. lightweightSR_DIV2K_s64w8_SwinIR_S_x4 = 2
  1620. realSR_BSRGAN_DFOWMFC_s64w8_SwinIR_L_x4_GAN = 3
  1621. # unused
  1622. realSR_BSRGAN_DFOWMFC_s64w8_SwinIR_L_x4_PSNR = 5
  1623. classicalSR_DF2K_s64w8_SwinIR_M_x2 = 6
  1624. classicalSR_DF2K_s64w8_SwinIR_M_x3 = 7
  1625. classicalSR_DF2K_s64w8_SwinIR_M_x4 = 8
  1626. classicalSR_DF2K_s64w8_SwinIR_M_x8 = 9
  1627. realSR_BSRGAN_DFO_s64w8_SwinIR_M_x2_GAN = 10
  1628. realSR_BSRGAN_DFO_s64w8_SwinIR_M_x2_PSNR = 11
  1629. realSR_BSRGAN_DFO_s64w8_SwinIR_M_x4_GAN = 12
  1630. realSR_BSRGAN_DFO_s64w8_SwinIR_M_x4_PSNR = 13
  1631. grayDN_DFWB_s128w8_SwinIR_M_noise15 = 14
  1632. grayDN_DFWB_s128w8_SwinIR_M_noise25 = 15
  1633. grayDN_DFWB_s128w8_SwinIR_M_noise50 = 16
  1634. colorDN_DFWB_s128w8_SwinIR_M_noise15 = 17
  1635. colorDN_DFWB_s128w8_SwinIR_M_noise25 = 18
  1636. colorDN_DFWB_s128w8_SwinIR_M_noise50 = 19
  1637. CAR_DFWB_s126w7_SwinIR_M_jpeg10 = 20
  1638. CAR_DFWB_s126w7_SwinIR_M_jpeg20 = 21
  1639. CAR_DFWB_s126w7_SwinIR_M_jpeg30 = 22
  1640. CAR_DFWB_s126w7_SwinIR_M_jpeg40 = 23
  1641. colorCAR_DFWB_s126w7_SwinIR_M_jpeg10 = 24
  1642. colorCAR_DFWB_s126w7_SwinIR_M_jpeg20 = 25
  1643. colorCAR_DFWB_s126w7_SwinIR_M_jpeg30 = 26
  1644. colorCAR_DFWB_s126w7_SwinIR_M_jpeg40 = 27
  1645.  
  1646.  
  1647. def SwinIR(
  1648. clip: vs.VideoNode,
  1649. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1650. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1651. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1652. model: SwinIRModel = SwinIRModel.lightweightSR_DIV2K_s64w8_SwinIR_S_x2,
  1653. backend: backendT = Backend.OV_CPU()
  1654. ) -> vs.VideoNode:
  1655. """ SwinIR: Image Restoration Using Swin Transformer """
  1656.  
  1657. func_name = "vsmlrt.SwinIR"
  1658.  
  1659. if not isinstance(clip, vs.VideoNode):
  1660. raise TypeError(f'{func_name}: "clip" must be a clip!')
  1661.  
  1662. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  1663. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  1664.  
  1665. if not isinstance(model, int) or model not in SwinIRModel.__members__.values():
  1666. raise ValueError(f'{func_name}: invalid "model"')
  1667.  
  1668. if model in range(14, 17) or model in range(20, 24):
  1669. if clip.format.color_family != vs.GRAY:
  1670. raise ValueError(f'{func_name}: "clip" must be of GRAY color family')
  1671. elif clip.format.color_family != vs.RGB:
  1672. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  1673.  
  1674. if overlap is None:
  1675. overlap_w = overlap_h = 16
  1676. elif isinstance(overlap, int):
  1677. overlap_w = overlap_h = overlap
  1678. else:
  1679. overlap_w, overlap_h = overlap
  1680.  
  1681. multiple = 1
  1682.  
  1683. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  1684. tiles=tiles, tilesize=tilesize,
  1685. width=clip.width, height=clip.height,
  1686. multiple=multiple,
  1687. overlap_w=overlap_w, overlap_h=overlap_h
  1688. )
  1689.  
  1690. if tile_w % multiple != 0 or tile_h % multiple != 0:
  1691. raise ValueError(
  1692. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  1693. )
  1694.  
  1695. backend = init_backend(
  1696. backend=backend,
  1697. trt_opt_shapes=(tile_w, tile_h)
  1698. )
  1699.  
  1700. if model < 4:
  1701. model_name = tuple(SwinIRModel.__members__)[model]
  1702. else:
  1703. model_name = tuple(SwinIRModel.__members__)[model - 1]
  1704.  
  1705. model_name = model_name.replace("SwinIR_", "SwinIR-")
  1706.  
  1707. if model in range(3):
  1708. model_name = f"002_{model_name}"
  1709. elif model in (3, 5):
  1710. model_name = f"003_{model_name}"
  1711. elif model in range(6, 10):
  1712. model_name = f"001_{model_name}"
  1713. elif model in range(10, 14):
  1714. model_name = f"003_{model_name}"
  1715. elif model in range(14, 17):
  1716. model_name = f"004_{model_name}"
  1717. elif model in range(17, 20):
  1718. model_name = f"005_{model_name}"
  1719. elif model in range(20, 28):
  1720. model_name = f"006_{model_name}"
  1721.  
  1722. network_path = os.path.join(
  1723. models_path,
  1724. "swinir",
  1725. f"{model_name}.onnx"
  1726. )
  1727.  
  1728. clip = inference_with_fallback(
  1729. clips=[clip], network_path=network_path,
  1730. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1731. backend=backend
  1732. )
  1733.  
  1734. return clip
  1735.  
  1736.  
  1737. @enum.unique
  1738. class ArtCNNModel(enum.IntEnum):
  1739. ArtCNN_C4F32 = 0
  1740. ArtCNN_C4F32_DS = 1
  1741. ArtCNN_C16F64 = 2
  1742. ArtCNN_C16F64_DS = 3
  1743. ArtCNN_C4F32_Chroma = 4
  1744. ArtCNN_C16F64_Chroma = 5
  1745. ArtCNN_R16F96 = 6
  1746. ArtCNN_R8F64 = 7
  1747. ArtCNN_R8F64_DS = 8
  1748. ArtCNN_R8F64_Chroma = 9
  1749. ArtCNN_C4F16 = 10
  1750. ArtCNN_C4F16_DS = 11
  1751. ArtCNN_R16F96_Chroma = 12
  1752. ArtCNN_C4F16_DN = 13
  1753. ArtCNN_C4F32_DN = 14
  1754. ArtCNN_R8F64_JPEG420 = 15
  1755. ArtCNN_R8F64_JPEG444 = 16
  1756. ArtCNN_R8F64_Chroma_DN = 17
  1757.  
  1758.  
  1759. def ArtCNN(
  1760. clip: vs.VideoNode,
  1761. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1762. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1763. overlap: typing.Optional[typing.Union[int, typing.Tuple[int, int]]] = None,
  1764. model: ArtCNNModel = ArtCNNModel.ArtCNN_C16F64,
  1765. backend: backendT = Backend.OV_CPU()
  1766. ) -> vs.VideoNode:
  1767. """ ArtCNN (https://github.com/Artoriuz/ArtCNN) """
  1768.  
  1769. func_name = "vsmlrt.ArtCNN"
  1770.  
  1771. if not isinstance(clip, vs.VideoNode):
  1772. raise TypeError(f'{func_name}: "clip" must be a clip!')
  1773.  
  1774. if clip.format.sample_type != vs.FLOAT or clip.format.bits_per_sample not in [16, 32]:
  1775. raise ValueError(f"{func_name}: only constant format 16/32 bit float input supported")
  1776.  
  1777. if not isinstance(model, int) or model not in ArtCNNModel.__members__.values():
  1778. raise ValueError(f'{func_name}: invalid "model"')
  1779.  
  1780. if model in (
  1781. ArtCNNModel.ArtCNN_C4F32_Chroma,
  1782. ArtCNNModel.ArtCNN_C16F64_Chroma,
  1783. ArtCNNModel.ArtCNN_R8F64_Chroma,
  1784. ArtCNNModel.ArtCNN_R16F96_Chroma,
  1785. ArtCNNModel.ArtCNN_R8F64_Chroma_DN,
  1786. ):
  1787. if clip.format.color_family != vs.YUV:
  1788. raise ValueError(f'{func_name}: "clip" must be of YUV color family')
  1789. if clip.format.subsampling_h != 0 or clip.format.subsampling_w != 0:
  1790. raise ValueError(
  1791. f'{func_name}: "clip" must be without subsampling! '
  1792. 'Bilinear upsampling is recommended.'
  1793. )
  1794. elif model in (
  1795. ArtCNNModel.ArtCNN_R8F64_JPEG420,
  1796. ArtCNNModel.ArtCNN_R8F64_JPEG444,
  1797. ):
  1798. if clip.format.color_family != vs.RGB:
  1799. raise ValueError(f'{func_name}: "clip" must be of RGB color family')
  1800. elif clip.format.color_family != vs.GRAY:
  1801. raise ValueError(f'{func_name}: "clip" must be of GRAY color family')
  1802.  
  1803. if overlap is None:
  1804. overlap_w = overlap_h = 8
  1805. elif isinstance(overlap, int):
  1806. overlap_w = overlap_h = overlap
  1807. else:
  1808. overlap_w, overlap_h = overlap
  1809.  
  1810. multiple = 1
  1811.  
  1812. (tile_w, tile_h), (overlap_w, overlap_h) = calc_tilesize(
  1813. tiles=tiles, tilesize=tilesize,
  1814. width=clip.width, height=clip.height,
  1815. multiple=multiple,
  1816. overlap_w=overlap_w, overlap_h=overlap_h
  1817. )
  1818.  
  1819. if tile_w % multiple != 0 or tile_h % multiple != 0:
  1820. raise ValueError(
  1821. f'{func_name}: tile size must be divisible by {multiple} ({tile_w}, {tile_h})'
  1822. )
  1823.  
  1824. backend = init_backend(
  1825. backend=backend,
  1826. trt_opt_shapes=(tile_w, tile_h)
  1827. )
  1828.  
  1829. model_name = tuple(ArtCNNModel.__members__)[model]
  1830.  
  1831. network_path = os.path.join(
  1832. models_path,
  1833. "ArtCNN",
  1834. f"{model_name}.onnx"
  1835. )
  1836.  
  1837. if model in (
  1838. ArtCNNModel.ArtCNN_C4F32_Chroma,
  1839. ArtCNNModel.ArtCNN_C16F64_Chroma,
  1840. ArtCNNModel.ArtCNN_R8F64_Chroma,
  1841. ArtCNNModel.ArtCNN_R16F96_Chroma,
  1842. ArtCNNModel.ArtCNN_R8F64_Chroma_DN,
  1843. ):
  1844. clip = _expr(clip, ["", "x 0.5 +"])
  1845.  
  1846. clip_u, clip_v = flexible_inference_with_fallback(
  1847. clips=[clip], network_path=network_path,
  1848. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1849. backend=backend
  1850. )
  1851.  
  1852. clip = core.std.ShufflePlanes([clip, clip_u, clip_v], [0, 0, 0], vs.YUV)
  1853.  
  1854. clip = _expr(clip, ["", "x 0.5 -"])
  1855. else:
  1856. clip = inference_with_fallback(
  1857. clips=[clip], network_path=network_path,
  1858. overlap=(overlap_w, overlap_h), tilesize=(tile_w, tile_h),
  1859. backend=backend
  1860. )
  1861.  
  1862. return clip
  1863.  
  1864.  
  1865. def get_engine_path(
  1866. network_path: str,
  1867. min_shapes: typing.Tuple[int, int],
  1868. opt_shapes: typing.Tuple[int, int],
  1869. max_shapes: typing.Tuple[int, int],
  1870. workspace: typing.Optional[int],
  1871. fp16: bool,
  1872. use_cublas: bool,
  1873. static_shape: bool,
  1874. tf32: bool,
  1875. use_cudnn: bool,
  1876. input_format: int,
  1877. output_format: int,
  1878. builder_optimization_level: int,
  1879. max_aux_streams: typing.Optional[int],
  1880. short_path: typing.Optional[bool],
  1881. bf16: bool,
  1882. engine_folder: typing.Optional[str],
  1883. is_rtx: bool = False,
  1884. trt_version: typing.Tuple[int, int, int] = (0, 0, 0),
  1885. device_name: str = "",
  1886. ) -> str:
  1887.  
  1888. with open(network_path, "rb") as file:
  1889. checksum = zlib.adler32(file.read())
  1890.  
  1891. if static_shape:
  1892. shape_str = f"{opt_shapes[0]}x{opt_shapes[1]}"
  1893. else:
  1894. shape_str = (
  1895. f"min{min_shapes[0]}x{min_shapes[1]}"
  1896. f"_opt{opt_shapes[0]}x{opt_shapes[1]}"
  1897. f"_max{max_shapes[0]}x{max_shapes[1]}"
  1898. )
  1899.  
  1900. identity = (
  1901. shape_str +
  1902. ("_fp16" if fp16 else "") +
  1903. ("_tf32" if tf32 else "") +
  1904. ("_bf16" if bf16 else "") +
  1905. (f"_workspace{workspace}" if workspace is not None else "") +
  1906. f"_opt{builder_optimization_level}" +
  1907. (f"_max-aux-streams{max_aux_streams}" if max_aux_streams is not None else "") +
  1908. "_trt-" + '.'.join(map(str, trt_version)) +
  1909. ("_cublas" if use_cublas else "") +
  1910. ("_cudnn" if use_cudnn else "") +
  1911. "_I-" + ("fp32" if input_format == 0 else "fp16") +
  1912. "_O-" + ("fp32" if output_format == 0 else "fp16") +
  1913. f"_{device_name}" +
  1914. ("_rtx" if is_rtx else "") +
  1915. f"_{checksum:x}"
  1916. )
  1917.  
  1918. dirname, basename = os.path.split(network_path)
  1919.  
  1920. if engine_folder is not None:
  1921. os.makedirs(engine_folder, exist_ok=True)
  1922. dirname = engine_folder
  1923.  
  1924. use_short_path = False
  1925.  
  1926. if short_path:
  1927. use_short_path = True
  1928. elif platform.system() == "Windows":
  1929. # use short path by default
  1930. if short_path is None:
  1931. use_short_path = True
  1932. # NTFS limitation
  1933. elif len(f"{basename}.{identity}.engine.cache.lock") >= 256:
  1934. use_short_path = True
  1935.  
  1936. if use_short_path:
  1937. return os.path.join(dirname, f"{zlib.crc32((f'{basename}.{identity}').encode()):x}.engine")
  1938. else:
  1939. return f"{os.path.join(dirname, basename)}.{identity}.engine"
  1940.  
  1941.  
  1942. def convert_model(
  1943. network_path: str,
  1944. target_network_path: str,
  1945. fp16: bool = False,
  1946. bf16: bool = False,
  1947. input_format: int = 0,
  1948. output_format: int = 0,
  1949. ):
  1950.  
  1951. if not any((fp16, bf16)):
  1952. raise ValueError("at least one target precision must be specified")
  1953.  
  1954. if bf16:
  1955. raise NotImplementedError("bf16 not supported yet")
  1956.  
  1957. if input_format != output_format:
  1958. raise ValueError("input format must be equal to output format")
  1959. else:
  1960. fp16_io = output_format == 1
  1961.  
  1962. import onnx
  1963. model = onnx.load(network_path)
  1964. try:
  1965. from onnxconverter_common.float16 import convert_float_to_float16
  1966. with warnings.catch_warnings():
  1967. warnings.simplefilter("ignore")
  1968. model = convert_float_to_float16(model, keep_io_types=not fp16_io)
  1969. except Exception:
  1970. import logging
  1971. from modelopt.onnx.autocast import convert_to_f16, configure_logging
  1972. configure_logging(logging.ERROR)
  1973. model = convert_to_f16(model, keep_io_types=not fp16_io)
  1974. onnx.save(model, target_network_path)
  1975.  
  1976.  
  1977. def trtexec(
  1978. network_path: str,
  1979. channels: int,
  1980. opt_shapes: typing.Tuple[int, int],
  1981. max_shapes: typing.Tuple[int, int],
  1982. fp16: bool,
  1983. device_id: int,
  1984. workspace: typing.Optional[int] = None,
  1985. verbose: bool = False,
  1986. use_cuda_graph: bool = False,
  1987. use_cublas: bool = False,
  1988. static_shape: bool = True,
  1989. tf32: bool = False,
  1990. log: bool = False,
  1991. use_cudnn: bool = False,
  1992. use_edge_mask_convolutions: bool = True,
  1993. use_jit_convolutions: bool = True,
  1994. heuristic: bool = False,
  1995. input_name: str = "input",
  1996. input_format: int = 0,
  1997. output_format: int = 0,
  1998. min_shapes: typing.Tuple[int, int] = (0, 0),
  1999. faster_dynamic_shapes: bool = True,
  2000. force_fp16: bool = False,
  2001. builder_optimization_level: int = 3,
  2002. max_aux_streams: typing.Optional[int] = None,
  2003. short_path: typing.Optional[bool] = None,
  2004. bf16: bool = False,
  2005. custom_env: typing.Dict[str, str] = {},
  2006. custom_args: typing.List[str] = [],
  2007. engine_folder: typing.Optional[str] = None,
  2008. max_tactics: typing.Optional[int] = None,
  2009. tiling_optimization_level: int = 0,
  2010. l2_limit_for_tiling: int = -1,
  2011. ) -> str:
  2012.  
  2013. # tensort runtime version
  2014. trt_version = parse_trt_version(int(core.trt.Version()["tensorrt_version"]))
  2015.  
  2016. if isinstance(opt_shapes, int):
  2017. opt_shapes = (opt_shapes, opt_shapes)
  2018.  
  2019. if isinstance(max_shapes, int):
  2020. max_shapes = (max_shapes, max_shapes)
  2021.  
  2022. if force_fp16:
  2023. fp16 = True
  2024. tf32 = False
  2025. bf16 = False
  2026.  
  2027. try:
  2028. device_name = core.trt.DeviceProperties(device_id)["name"].decode()
  2029. device_name = device_name.replace(' ', '-')
  2030. except AttributeError:
  2031. device_name = f"device{device_id}"
  2032.  
  2033. engine_path = get_engine_path(
  2034. network_path=network_path,
  2035. min_shapes=min_shapes,
  2036. opt_shapes=opt_shapes,
  2037. max_shapes=max_shapes,
  2038. workspace=workspace,
  2039. fp16=fp16,
  2040. use_cublas=use_cublas,
  2041. static_shape=static_shape,
  2042. tf32=tf32,
  2043. use_cudnn=use_cudnn,
  2044. input_format=input_format,
  2045. output_format=output_format,
  2046. builder_optimization_level=builder_optimization_level,
  2047. max_aux_streams=max_aux_streams,
  2048. short_path=short_path,
  2049. bf16=bf16,
  2050. engine_folder=engine_folder,
  2051. trt_version=trt_version,
  2052. device_name=device_name,
  2053. )
  2054.  
  2055. if os.access(engine_path, mode=os.R_OK) and os.path.getsize(engine_path) >= 1024:
  2056. return engine_path
  2057.  
  2058. # do not consider alternative path when the engine_folder is given
  2059. if engine_folder is None:
  2060. alter_engine_path = os.path.join(
  2061. tempfile.gettempdir(),
  2062. os.path.splitdrive(engine_path)[1][1:]
  2063. )
  2064.  
  2065. if os.access(alter_engine_path, mode=os.R_OK) and os.path.getsize(alter_engine_path) >= 1024:
  2066. return alter_engine_path
  2067.  
  2068. try:
  2069. # test writability
  2070. with open(engine_path, "w") as f:
  2071. pass
  2072. os.remove(engine_path)
  2073. except PermissionError:
  2074. if engine_folder is None:
  2075. print(f"{engine_path} is not writable", file=sys.stderr)
  2076. engine_path = alter_engine_path
  2077. dirname = os.path.dirname(engine_path)
  2078. if not os.path.exists(dirname):
  2079. os.makedirs(dirname)
  2080. print(f"change engine path to {engine_path}", file=sys.stderr)
  2081. else:
  2082. # do not consider alternative path when the engine_folder is given
  2083. raise PermissionError(f"{engine_path} is not writable")
  2084.  
  2085. if any((fp16, bf16)) and trt_version >= (11, 0, 0):
  2086. target_network_path = f"{engine_path}.onnx"
  2087. convert_model(
  2088. network_path=network_path,
  2089. target_network_path=f"{engine_path}.onnx",
  2090. fp16=fp16,
  2091. bf16=bf16,
  2092. input_format=input_format,
  2093. output_format=output_format,
  2094. )
  2095. network_path = target_network_path
  2096.  
  2097. args = [
  2098. trtexec_path,
  2099. f"--onnx={network_path}",
  2100. f"--timingCacheFile={engine_path}.cache",
  2101. f"--device={device_id}",
  2102. f"--saveEngine={engine_path}"
  2103. ]
  2104.  
  2105. if workspace is not None:
  2106. if trt_version >= (8, 4, 0):
  2107. args.append(f"--memPoolSize=workspace:{workspace}")
  2108. else:
  2109. args.append(f"--workspace{workspace}")
  2110.  
  2111. if static_shape:
  2112. args.append(f"--shapes={input_name}:1x{channels}x{opt_shapes[1]}x{opt_shapes[0]}")
  2113. else:
  2114. args.extend([
  2115. f"--minShapes={input_name}:1x{channels}x{min_shapes[1]}x{min_shapes[0]}",
  2116. f"--optShapes={input_name}:1x{channels}x{opt_shapes[1]}x{opt_shapes[0]}",
  2117. f"--maxShapes={input_name}:1x{channels}x{max_shapes[1]}x{max_shapes[0]}"
  2118. ])
  2119.  
  2120. if fp16 and trt_version < (11, 0, 0):
  2121. args.append("--fp16")
  2122.  
  2123. if verbose:
  2124. args.append("--verbose")
  2125.  
  2126. preview_features = []
  2127. if (use_cublas or use_cudnn) and (8, 6, 0) <= trt_version < (10, 0, 0):
  2128. preview_features.append("-disableExternalTacticSourcesForCore0805")
  2129.  
  2130. if preview_features and trt_version >= (8, 5, 0):
  2131. args.append(f"--preview={','.join(preview_features)}")
  2132.  
  2133. tactic_sources = []
  2134.  
  2135. if trt_version < (11, 0, 0):
  2136. if use_cublas:
  2137. tactic_sources.extend(["+CUBLAS", "+CUBLAS_LT"])
  2138. else:
  2139. tactic_sources.extend(["-CUBLAS", "-CUBLAS_LT"])
  2140.  
  2141. if trt_version < (11, 0, 0):
  2142. if use_cudnn:
  2143. tactic_sources.append("+CUDNN")
  2144. else:
  2145. tactic_sources.append("-CUDNN")
  2146.  
  2147. if trt_version >= (8, 4, 1):
  2148. if use_edge_mask_convolutions:
  2149. tactic_sources.append("+EDGE_MASK_CONVOLUTIONS")
  2150. else:
  2151. tactic_sources.append("-EDGE_MASK_CONVOLUTIONS")
  2152.  
  2153. if trt_version >= (8, 5, 0):
  2154. if use_jit_convolutions:
  2155. tactic_sources.append("+JIT_CONVOLUTIONS")
  2156. else:
  2157. tactic_sources.append("-JIT_CONVOLUTIONS")
  2158.  
  2159. args.append(f"--tacticSources={','.join(tactic_sources)}")
  2160.  
  2161. if use_cuda_graph:
  2162. if trt_version < (11, 0, 0):
  2163. args.extend((
  2164. "--useCudaGraph",
  2165. "--noDataTransfers"
  2166. ))
  2167. else:
  2168. if trt_version >= (11, 0, 0):
  2169. args.append("--noCudaGraph")
  2170.  
  2171. if trt_version >= (8, 6, 0):
  2172. args.append("--skipInference")
  2173. else:
  2174. args.append("--buildOnly")
  2175.  
  2176. if not tf32 and trt_version < (11, 0, 0):
  2177. args.append("--noTF32")
  2178.  
  2179. if heuristic and trt_version >= (8, 5, 0) and core.trt.DeviceProperties(device_id)["major"] >= 8:
  2180. if trt_version < (8, 6, 0):
  2181. args.append("--heuristic")
  2182. else:
  2183. builder_optimization_level = 2
  2184.  
  2185. if trt_version < (11, 0, 0):
  2186. args.extend([
  2187. "--inputIOFormats=fp32:chw" if input_format == 0 else "--inputIOFormats=fp16:chw",
  2188. "--outputIOFormats=fp32:chw" if output_format == 0 else "--outputIOFormats=fp16:chw"
  2189. ])
  2190.  
  2191. if faster_dynamic_shapes and not static_shape and (8, 5, 0) <= trt_version < (8, 6, 0):
  2192. args.append("--preview=+fasterDynamicShapes0805")
  2193.  
  2194. if force_fp16:
  2195. if (8, 4, 1) <= trt_version < (11, 0, 0):
  2196. args.extend([
  2197. "--layerPrecisions=*:fp16",
  2198. "--layerOutputTypes=*:fp16",
  2199. "--precisionConstraints=obey"
  2200. ])
  2201. else:
  2202. raise ValueError('"force_fp16" is not available')
  2203.  
  2204. if trt_version >= (8, 6, 0):
  2205. args.append(f"--builderOptimizationLevel={builder_optimization_level}")
  2206.  
  2207. if max_aux_streams is not None:
  2208. args.append(f"--maxAuxStreams={max_aux_streams}")
  2209.  
  2210. if (9, 0, 0) <= trt_version < (11, 0, 0):
  2211. if bf16:
  2212. args.append("--bf16")
  2213.  
  2214. if trt_version >= (10, 4, 0):
  2215. if max_tactics is not None:
  2216. args.append(f"--maxTactics={max_tactics}")
  2217.  
  2218. if trt_version >= (10, 8, 0) and tiling_optimization_level != 0:
  2219. args.append(f"--tilingOptimizationLevel={tiling_optimization_level}")
  2220. args.append(f"--l2LimitForTiling={l2_limit_for_tiling}")
  2221.  
  2222. args.extend(custom_args)
  2223.  
  2224. if log:
  2225. env_key = "TRTEXEC_LOG_FILE"
  2226. prev_env_value = os.environ.get(env_key)
  2227.  
  2228. if prev_env_value is not None and len(prev_env_value) > 0:
  2229. # env_key has been set, no extra action
  2230. env = {env_key: prev_env_value, "CUDA_MODULE_LOADING": "LAZY"}
  2231. env.update(**custom_env)
  2232. subprocess.run(args, env=env, check=True, stdout=sys.stderr)
  2233. else:
  2234. time_str = time.strftime('%y%m%d_%H%M%S', time.localtime())
  2235.  
  2236. log_filename = os.path.join(
  2237. tempfile.gettempdir(),
  2238. f"trtexec_{time_str}.log"
  2239. )
  2240.  
  2241. env = {env_key: log_filename, "CUDA_MODULE_LOADING": "LAZY"}
  2242. env.update(**custom_env)
  2243.  
  2244. completed_process = subprocess.run(args, env=env, check=False, stdout=sys.stderr)
  2245.  
  2246. if completed_process.returncode == 0:
  2247. try:
  2248. os.remove(log_filename)
  2249. except FileNotFoundError:
  2250. # maybe the official trtexec is used?
  2251. pass
  2252. else:
  2253. if os.path.exists(log_filename):
  2254. raise RuntimeError(f"trtexec execution fails, log has been written to {log_filename}")
  2255. else:
  2256. raise RuntimeError(f"trtexec execution fails but no log is found")
  2257. else:
  2258. env = {"CUDA_MODULE_LOADING": "LAZY"}
  2259. env.update(**custom_env)
  2260. subprocess.run(args, env=env, check=True, stdout=sys.stderr)
  2261.  
  2262. return engine_path
  2263.  
  2264.  
  2265. def get_mxr_path(
  2266. network_path: str,
  2267. opt_shapes: typing.Tuple[int, int],
  2268. fp16: bool,
  2269. fast_math: bool,
  2270. exhaustive_tune: bool,
  2271. device_id: int,
  2272. short_path: typing.Optional[bool],
  2273. bf16: bool,
  2274. ) -> str:
  2275.  
  2276. with open(network_path, "rb") as file:
  2277. checksum = zlib.adler32(file.read())
  2278.  
  2279. migx_version = core.migx.Version()["migraphx_version_build"].decode()
  2280.  
  2281. try:
  2282. device_name = core.migx.DeviceProperties(device_id)["name"].decode()
  2283. device_name = device_name.replace(' ', '-')
  2284. except AttributeError:
  2285. device_name = f"device{device_id}"
  2286.  
  2287. shape_str = f"{opt_shapes[0]}x{opt_shapes[1]}"
  2288.  
  2289. identity = (
  2290. shape_str +
  2291. ("_fp16" if fp16 else "") +
  2292. ("_bf16" if bf16 else "") +
  2293. ("_fast" if fast_math else "") +
  2294. ("_exhaustive" if exhaustive_tune else "") +
  2295. f"_migx-{migx_version}" +
  2296. f"_{device_name}" +
  2297. f"_{checksum:x}"
  2298. )
  2299.  
  2300. if short_path or (short_path is None and platform.system() == "Windows"):
  2301. dirname, basename = os.path.split(network_path)
  2302. return os.path.join(dirname, f"{zlib.crc32((basename + identity).encode()):x}.mxr")
  2303. else:
  2304. return f"{network_path}.{identity}.mxr"
  2305.  
  2306.  
  2307. def migraphx_driver(
  2308. network_path: str,
  2309. channels: int,
  2310. opt_shapes: typing.Tuple[int, int],
  2311. fp16: bool,
  2312. fast_math: bool,
  2313. exhaustive_tune: bool,
  2314. device_id: int,
  2315. input_name: str = "input",
  2316. short_path: typing.Optional[bool] = None,
  2317. custom_env: typing.Dict[str, str] = {},
  2318. custom_args: typing.List[str] = [],
  2319. bf16: bool = False,
  2320. ) -> str:
  2321.  
  2322. if isinstance(opt_shapes, int):
  2323. opt_shapes = (opt_shapes, opt_shapes)
  2324.  
  2325. mxr_path = get_mxr_path(
  2326. network_path=network_path,
  2327. opt_shapes=opt_shapes,
  2328. fp16=fp16,
  2329. fast_math=fast_math,
  2330. exhaustive_tune=exhaustive_tune,
  2331. device_id=device_id,
  2332. short_path=short_path,
  2333. bf16=bf16,
  2334. )
  2335.  
  2336. if os.access(mxr_path, mode=os.R_OK) and os.path.getsize(mxr_path) >= 1024:
  2337. return mxr_path
  2338.  
  2339. alter_mxr_path = os.path.join(
  2340. tempfile.gettempdir(),
  2341. os.path.splitdrive(mxr_path)[1][1:]
  2342. )
  2343.  
  2344. if os.access(alter_mxr_path, mode=os.R_OK) and os.path.getsize(mxr_path) >= 1024:
  2345. return alter_mxr_path
  2346.  
  2347. try:
  2348. # test writability
  2349. with open(mxr_path, "w") as f:
  2350. pass
  2351. os.remove(mxr_path)
  2352. except PermissionError:
  2353. print(f"{mxr_path} not writable", file=sys.stderr)
  2354. mxr_path = alter_mxr_path
  2355. dirname = os.path.dirname(mxr_path)
  2356. if not os.path.exists(dirname):
  2357. os.makedirs(dirname)
  2358. print(f"change mxr path to {mxr_path}", file=sys.stderr)
  2359.  
  2360. if device_id != 0:
  2361. raise ValueError('"device_id" must be 0')
  2362.  
  2363. args = [
  2364. migraphx_driver_path,
  2365. "compile",
  2366. "--onnx", f"{network_path}",
  2367. "--gpu",
  2368. # f"--device={device_id}",
  2369. "--optimize",
  2370. "--binary",
  2371. "--output", f"{mxr_path}"
  2372. ]
  2373.  
  2374. args.extend(["--input-dim", f"@{input_name}", "1", f"{channels}", f"{opt_shapes[1]}", f"{opt_shapes[0]}"])
  2375.  
  2376. if fp16:
  2377. args.append("--fp16")
  2378.  
  2379. if not fast_math:
  2380. args.append("--disable-fast-math")
  2381.  
  2382. if exhaustive_tune:
  2383. args.append("--exhaustive-tune")
  2384.  
  2385. # bf16 support is introduced in ROCm 7.2.0, but the version info from the vsmigx library may not be reliable.
  2386. if bf16:
  2387. args.append("--bf16")
  2388.  
  2389. args.extend(custom_args)
  2390.  
  2391. subprocess.run(args, env=custom_env, check=True, stdout=sys.stderr)
  2392.  
  2393. return mxr_path
  2394.  
  2395.  
  2396. def tensorrt_rtx(
  2397. network_path: str,
  2398. channels: int,
  2399. fp16: bool,
  2400. device_id: int,
  2401. opt_shapes: typing.Tuple[int, int],
  2402. max_shapes: typing.Tuple[int, int],
  2403. workspace: typing.Optional[int] = None,
  2404. verbose: bool = False,
  2405. use_cuda_graph: bool = False,
  2406. static_shape: bool = True,
  2407. min_shapes: typing.Tuple[int, int] = (0, 0),
  2408. use_cudnn: bool = False,
  2409. use_edge_mask_convolutions: bool = True,
  2410. input_name: str = "input",
  2411. builder_optimization_level: int = 3,
  2412. max_aux_streams: typing.Optional[int] = None,
  2413. short_path: typing.Optional[bool] = None,
  2414. custom_env: typing.Dict[str, str] = {},
  2415. custom_args: typing.List[str] = [],
  2416. engine_folder: typing.Optional[str] = None,
  2417. max_tactics: typing.Optional[int] = None,
  2418. tiling_optimization_level: int = 0,
  2419. l2_limit_for_tiling: int = -1,
  2420. fp16_io: bool = False,
  2421. ) -> str:
  2422.  
  2423. # tensort runtime version
  2424. trt_version = parse_trt_version(int(core.trt_rtx.Version()["tensorrt_version"]))
  2425.  
  2426. if fp16:
  2427. with open(network_path, "rb") as file:
  2428. checksum = zlib.adler32(file.read())
  2429.  
  2430. dirname, basename = os.path.split(network_path)
  2431.  
  2432. if engine_folder is not None:
  2433. os.makedirs(engine_folder, exist_ok=True)
  2434. dirname = engine_folder
  2435.  
  2436. fp16_network_path = f"{os.path.join(dirname, basename)}_{checksum}_fp16{'_io' if fp16_io else ''}.onnx"
  2437. if not (os.access(fp16_network_path, mode=os.R_OK) and os.path.getsize(fp16_network_path) >= 1024):
  2438. convert_model(
  2439. network_path=network_path,
  2440. target_network_path=fp16_network_path,
  2441. fp16=True,
  2442. input_format=1-fp16_io,
  2443. output_format=1-fp16_io
  2444. )
  2445. network_path = fp16_network_path
  2446. elif fp16_io:
  2447. raise ValueError('tensorrt_rtx: "fp16" must be True.')
  2448.  
  2449. try:
  2450. device_name = core.trt_rtx.DeviceProperties(device_id)["name"].decode()
  2451. device_name = device_name.replace(' ', '-')
  2452. except AttributeError:
  2453. device_name = f"device{device_id}"
  2454.  
  2455. engine_path = get_engine_path(
  2456. network_path=network_path,
  2457. min_shapes=min_shapes,
  2458. opt_shapes=opt_shapes,
  2459. max_shapes=max_shapes,
  2460. workspace=workspace,
  2461. fp16=fp16,
  2462. use_cublas=False,
  2463. static_shape=static_shape,
  2464. tf32=False,
  2465. use_cudnn=use_cudnn,
  2466. input_format=int(fp16_io),
  2467. output_format=int(fp16_io),
  2468. builder_optimization_level=builder_optimization_level,
  2469. max_aux_streams=max_aux_streams,
  2470. short_path=short_path,
  2471. bf16=False,
  2472. engine_folder=engine_folder,
  2473. is_rtx=True,
  2474. trt_version=trt_version,
  2475. device_name=device_name,
  2476. )
  2477.  
  2478. if os.access(engine_path, mode=os.R_OK) and os.path.getsize(engine_path) >= 1024:
  2479. return engine_path
  2480.  
  2481. # do not consider alternative path when the engine_folder is given
  2482. if engine_folder is None:
  2483. alter_engine_path = os.path.join(
  2484. tempfile.gettempdir(),
  2485. os.path.splitdrive(engine_path)[1][1:]
  2486. )
  2487.  
  2488. if os.access(alter_engine_path, mode=os.R_OK) and os.path.getsize(alter_engine_path) >= 1024:
  2489. return alter_engine_path
  2490.  
  2491. try:
  2492. # test writability
  2493. with open(engine_path, "w") as f:
  2494. pass
  2495. os.remove(engine_path)
  2496. except PermissionError:
  2497. if engine_folder is None:
  2498. print(f"{engine_path} is not writable", file=sys.stderr)
  2499. engine_path = alter_engine_path
  2500. dirname = os.path.dirname(engine_path)
  2501. if not os.path.exists(dirname):
  2502. os.makedirs(dirname)
  2503. print(f"change engine path to {engine_path}", file=sys.stderr)
  2504. else:
  2505. # do not consider alternative path when the engine_folder is given
  2506. raise PermissionError(f"{engine_path} is not writable")
  2507.  
  2508. args = [
  2509. tensorrt_rtx_path,
  2510. f"--onnx={network_path}",
  2511. f"--timingCacheFile={engine_path}.cache",
  2512. f"--device={device_id}",
  2513. f"--saveEngine={engine_path}",
  2514. "--useGpu",
  2515. ]
  2516.  
  2517. if workspace is not None:
  2518. args.append(f"--memPoolSize=workspace:{workspace}")
  2519.  
  2520. if static_shape:
  2521. args.append(f"--shapes={input_name}:1x{channels}x{opt_shapes[1]}x{opt_shapes[0]}")
  2522. else:
  2523. args.extend([
  2524. f"--minShapes={input_name}:1x{channels}x{min_shapes[1]}x{min_shapes[0]}",
  2525. f"--optShapes={input_name}:1x{channels}x{opt_shapes[1]}x{opt_shapes[0]}",
  2526. f"--maxShapes={input_name}:1x{channels}x{max_shapes[1]}x{max_shapes[0]}",
  2527. "--specializeStrategyDS=eager"
  2528. ])
  2529.  
  2530. if verbose:
  2531. args.append("--verbose")
  2532.  
  2533. tactic_sources = []
  2534.  
  2535. if use_cudnn:
  2536. tactic_sources.append("+CUDNN")
  2537. else:
  2538. tactic_sources.append("-CUDNN")
  2539.  
  2540. if use_edge_mask_convolutions:
  2541. tactic_sources.append("+EDGE_MASK_CONVOLUTIONS")
  2542. else:
  2543. tactic_sources.append("-EDGE_MASK_CONVOLUTIONS")
  2544.  
  2545. args.append(f"--tacticSources={','.join(tactic_sources)}")
  2546.  
  2547. if use_cuda_graph:
  2548. args.extend((
  2549. "--useCudaGraph",
  2550. "--noDataTransfers"
  2551. ))
  2552. else:
  2553. args.append("--skipInference")
  2554.  
  2555. args.append(f"--builderOptimizationLevel={builder_optimization_level}")
  2556.  
  2557. if max_aux_streams is not None:
  2558. args.append(f"--maxAuxStreams={max_aux_streams}")
  2559.  
  2560. if max_tactics is not None:
  2561. args.append(f"--maxTactics={max_tactics}")
  2562.  
  2563. if tiling_optimization_level != 0:
  2564. args.append(f"--tilingOptimizationLevel={tiling_optimization_level}")
  2565. args.append(f"--l2LimitForTiling={l2_limit_for_tiling}")
  2566.  
  2567. args.extend(custom_args)
  2568.  
  2569. env = {"CUDA_MODULE_LOADING": "LAZY"}
  2570. env.update(**custom_env)
  2571. subprocess.run(args, env=env, check=True, stdout=sys.stderr)
  2572.  
  2573. return engine_path
  2574.  
  2575.  
  2576. def calc_size(width: int, tiles: int, overlap: int, multiple: int = 1) -> int:
  2577. return math.ceil((width + 2 * overlap * (tiles - 1)) / (tiles * multiple)) * multiple
  2578.  
  2579.  
  2580. def calc_tilesize(
  2581. tiles: typing.Optional[typing.Union[int, typing.Tuple[int, int]]],
  2582. tilesize: typing.Optional[typing.Union[int, typing.Tuple[int, int]]],
  2583. width: int,
  2584. height: int,
  2585. multiple: int,
  2586. overlap_w: int,
  2587. overlap_h: int
  2588. ) -> typing.Tuple[typing.Tuple[int, int], typing.Tuple[int, int]]:
  2589.  
  2590. if tilesize is None:
  2591. if tiles is None:
  2592. overlap_w = 0
  2593. overlap_h = 0
  2594. tile_w = width
  2595. tile_h = height
  2596. elif isinstance(tiles, int):
  2597. tile_w = calc_size(width, tiles, overlap_w, multiple)
  2598. tile_h = calc_size(height, tiles, overlap_h, multiple)
  2599. else:
  2600. tile_w = calc_size(width, tiles[0], overlap_w, multiple)
  2601. tile_h = calc_size(height, tiles[1], overlap_h, multiple)
  2602. elif isinstance(tilesize, int):
  2603. tile_w = tilesize
  2604. tile_h = tilesize
  2605. else:
  2606. tile_w, tile_h = tilesize
  2607.  
  2608. return (tile_w, tile_h), (overlap_w, overlap_h)
  2609.  
  2610.  
  2611. def init_backend(
  2612. backend: backendT,
  2613. trt_opt_shapes: typing.Tuple[int, int]
  2614. ) -> backendT:
  2615.  
  2616. if backend is Backend.ORT_CPU: # type: ignore
  2617. backend = Backend.ORT_CPU()
  2618. elif backend is Backend.ORT_CUDA: # type: ignore
  2619. backend = Backend.ORT_CUDA()
  2620. elif backend is Backend.OV_CPU: # type: ignore
  2621. backend = Backend.OV_CPU()
  2622. elif backend is Backend.TRT: # type: ignore
  2623. backend = Backend.TRT()
  2624. elif backend is Backend.OV_GPU: # type: ignore
  2625. backend = Backend.OV_GPU()
  2626. elif backend is Backend.NCNN_VK: # type: ignore
  2627. backend = Backend.NCNN_VK()
  2628. elif backend is Backend.ORT_DML: # type: ignore
  2629. backend = Backend.ORT_DML()
  2630. elif backend is Backend.MIGX: # type: ignore
  2631. backend = Backend.MIGX()
  2632. elif backend is Backend.OV_NPU: # type: ignore
  2633. backend = Backend.OV_NPU()
  2634. elif backend is Backend.TRT_RTX: # type: ignore
  2635. backend = Backend.TRT_RTX()
  2636.  
  2637. backend = copy.deepcopy(backend)
  2638.  
  2639. if isinstance(backend, (Backend.TRT, Backend.TRT_RTX)):
  2640. if backend.opt_shapes is None:
  2641. backend.opt_shapes = trt_opt_shapes
  2642.  
  2643. if backend.max_shapes is None:
  2644. backend.max_shapes = backend.opt_shapes
  2645. elif isinstance(backend, Backend.MIGX):
  2646. if backend.opt_shapes is None:
  2647. backend.opt_shapes = trt_opt_shapes
  2648.  
  2649. return backend
  2650.  
  2651.  
  2652. def _inference(
  2653. clips: typing.List[vs.VideoNode],
  2654. network_path: typing.Union[bytes, str],
  2655. overlap: typing.Tuple[int, int],
  2656. tilesize: typing.Tuple[int, int],
  2657. backend: backendT,
  2658. path_is_serialization: bool = False,
  2659. input_name: str = "input",
  2660. flexible_output_prop: typing.Optional[str] = None,
  2661. batch_size: int = 1
  2662. ) -> typing.Union[vs.VideoNode, typing.Dict[str, typing.Any]]:
  2663.  
  2664. if not path_is_serialization:
  2665. network_path = typing.cast(str, network_path)
  2666. if not os.path.exists(network_path):
  2667. raise RuntimeError(
  2668. f'"{network_path}" not found, '
  2669. "built-in models can be found at "
  2670. "https://github.com/AmusementClub/vs-mlrt/releases/tag/model-20211209, "
  2671. "https://github.com/AmusementClub/vs-mlrt/releases/tag/model-20220923 and "
  2672. "https://github.com/AmusementClub/vs-mlrt/releases/tag/external-models"
  2673. )
  2674.  
  2675. if path_is_serialization:
  2676. if isinstance(backend, Backend.TRT):
  2677. raise ValueError('"path_is_serialization" must be False for trt backend')
  2678. elif isinstance(backend, Backend.MIGX):
  2679. raise ValueError('"path_is_serialization" must be False for migx backend')
  2680. elif isinstance(backend, Backend.TRT_RTX):
  2681. raise ValueError('"path_is_serialization" must be False for trt_rtx backend')
  2682.  
  2683. if not isinstance(batch_size, int) or batch_size < 1:
  2684. raise ValueError('"batch_size" must be a positve integer')
  2685.  
  2686. if batch_size > 1:
  2687. import numpy as np
  2688. import onnx
  2689.  
  2690. if path_is_serialization:
  2691. model = onnx.load_model_from_string(network_path)
  2692. else:
  2693. model = onnx.load(network_path)
  2694.  
  2695. graph = model.graph
  2696. in_channels = graph.input[0].type.tensor_type.shape.dim[1].dim_value
  2697. graph.input[0].type.tensor_type.shape.dim[1].dim_value *= batch_size
  2698. graph.output[0].type.tensor_type.shape.dim[1].dim_param = "_vsmlrt_output_channels"
  2699.  
  2700. input_name = graph.input[0].name
  2701. output_name = graph.output[0].name
  2702. for node in graph.node:
  2703. for i, name in enumerate(node.input):
  2704. if name == input_name:
  2705. node.input[i] = "_vsmlrt_input"
  2706.  
  2707. for i, name in enumerate(node.output):
  2708. if name == output_name:
  2709. node.output[i] = "_vsmlrt_output"
  2710.  
  2711. graph.node.insert(1, onnx.helper.make_node(
  2712. op_type="Constant",
  2713. inputs=[],
  2714. outputs=["_vsmlrt_input_shape"],
  2715. value=onnx.numpy_helper.from_array(np.array([-1, in_channels, 0, 0]))
  2716. ))
  2717. graph.node.insert(2, onnx.helper.make_node(
  2718. op_type="Reshape",
  2719. inputs=[input_name, "_vsmlrt_input_shape"],
  2720. outputs=["_vsmlrt_input"]
  2721. ))
  2722.  
  2723. graph.node.insert(-1, onnx.helper.make_node(
  2724. op_type="Constant",
  2725. inputs=[],
  2726. outputs=["_vsmlrt_output_shape"],
  2727. value=onnx.numpy_helper.from_array(np.array([1, -1, 0, 0]))
  2728. ))
  2729. graph.node.insert(-1, onnx.helper.make_node(
  2730. op_type="Reshape",
  2731. inputs=["_vsmlrt_output", "_vsmlrt_output_shape"],
  2732. outputs=[output_name]
  2733. ))
  2734.  
  2735. if backend.supports_onnx_serialization:
  2736. network_path = model.SerializeToString()
  2737. else:
  2738. network_path = f"{network_path}_batch{batch_size}.onnx"
  2739. onnx.save(model, network_path)
  2740.  
  2741. path_is_serialization = backend.supports_onnx_serialization
  2742.  
  2743. pad = (batch_size - clips[0].num_frames % batch_size) % batch_size
  2744. if pad:
  2745. clips = [clip.std.DuplicateFrames([clip.num_frames - 1] * pad) for clip in clips]
  2746.  
  2747. clips = [
  2748. clip[i::batch_size]
  2749. for i in range(batch_size)
  2750. for clip in clips
  2751. ]
  2752.  
  2753. flexible_output_prop_orig = flexible_output_prop
  2754.  
  2755. if flexible_output_prop is None:
  2756. flexible_output_prop = "vsmlrt_flexible_batch"
  2757.  
  2758. kwargs = dict(overlap=overlap, tilesize=tilesize)
  2759. if flexible_output_prop is not None:
  2760. kwargs["flexible_output_prop"] = flexible_output_prop
  2761.  
  2762. if isinstance(backend, (Backend.ORT_CPU, Backend.ORT_DML, Backend.ORT_COREML, Backend.ORT_CUDA)):
  2763. version_list = core.ort.Version().get("onnxruntime_version", b"0.0.0").split(b'.')
  2764. if len(version_list) != 3:
  2765. version = (0, 0, 0)
  2766. else:
  2767. version = tuple(map(int, version_list))
  2768.  
  2769. if version >= (1, 18, 0):
  2770. kwargs["output_format"] = backend.output_format
  2771.  
  2772. elif isinstance(backend, Backend.NCNN_VK):
  2773. if "output_format" in core.ncnn.Model.signature:
  2774. kwargs["output_format"] = backend.output_format
  2775.  
  2776. if isinstance(backend, Backend.ORT_CPU):
  2777. ret = core.ort.Model(
  2778. clips, network_path,
  2779. provider="CPU", builtin=False,
  2780. num_streams=backend.num_streams,
  2781. verbosity=backend.verbosity,
  2782. fp16=backend.fp16,
  2783. path_is_serialization=path_is_serialization,
  2784. fp16_blacklist_ops=backend.fp16_blacklist_ops,
  2785. **kwargs
  2786. )
  2787. elif isinstance(backend, Backend.ORT_DML):
  2788. ret = core.ort.Model(
  2789. clips, network_path,
  2790. provider="DML", builtin=False,
  2791. device_id=backend.device_id,
  2792. num_streams=backend.num_streams,
  2793. verbosity=backend.verbosity,
  2794. fp16=backend.fp16,
  2795. path_is_serialization=path_is_serialization,
  2796. fp16_blacklist_ops=backend.fp16_blacklist_ops,
  2797. **kwargs
  2798. )
  2799. elif isinstance(backend, Backend.ORT_COREML):
  2800. ret = core.ort.Model(
  2801. clips, network_path,
  2802. provider="COREML", builtin=False,
  2803. num_streams=backend.num_streams,
  2804. verbosity=backend.verbosity,
  2805. fp16=backend.fp16,
  2806. path_is_serialization=path_is_serialization,
  2807. fp16_blacklist_ops=backend.fp16_blacklist_ops,
  2808. ml_program=backend.ml_program,
  2809. **kwargs
  2810. )
  2811. elif isinstance(backend, Backend.ORT_CUDA):
  2812. version_list = core.ort.Version().get("onnxruntime_version", b"0.0.0").split(b'.')
  2813. if len(version_list) != 3:
  2814. version = (0, 0, 0)
  2815. else:
  2816. version = tuple(map(int, version_list))
  2817.  
  2818. if version >= (1, 18, 0):
  2819. kwargs["prefer_nhwc"] = backend.prefer_nhwc
  2820. kwargs["tf32"] = backend.tf32
  2821.  
  2822. ret = core.ort.Model(
  2823. clips, network_path,
  2824. provider="CUDA", builtin=False,
  2825. device_id=backend.device_id,
  2826. num_streams=backend.num_streams,
  2827. verbosity=backend.verbosity,
  2828. cudnn_benchmark=backend.cudnn_benchmark,
  2829. fp16=backend.fp16,
  2830. path_is_serialization=path_is_serialization,
  2831. use_cuda_graph=backend.use_cuda_graph,
  2832. fp16_blacklist_ops=backend.fp16_blacklist_ops,
  2833. **kwargs
  2834. )
  2835. elif isinstance(backend, Backend.OV_CPU):
  2836. version = tuple(map(int, core.ov.Version().get("openvino_version", b"0.0.0").split(b'-')[0].split(b'.')))
  2837.  
  2838. if version >= (2024, 0, 0):
  2839. config_dict = dict(
  2840. NUM_STREAMS=backend.num_streams,
  2841. INFERENCE_NUM_THREADS=backend.num_threads,
  2842. ENABLE_CPU_PINNING="YES" if backend.bind_thread else "NO"
  2843. )
  2844. if backend.fp16:
  2845. config_dict["INFERENCE_PRECISION_HINT"] = "f16"
  2846. elif backend.bf16:
  2847. config_dict["INFERENCE_PRECISION_HINT"] = "bf16"
  2848. else:
  2849. config_dict["INFERENCE_PRECISION_HINT"] = "f32"
  2850.  
  2851. config = lambda: config_dict
  2852. else:
  2853. config = lambda: dict(
  2854. CPU_THROUGHPUT_STREAMS=backend.num_streams,
  2855. CPU_BIND_THREAD="YES" if backend.bind_thread else "NO",
  2856. CPU_THREADS_NUM=backend.num_threads,
  2857. ENFORCE_BF16="YES" if backend.bf16 else "NO"
  2858. )
  2859.  
  2860. ret = core.ov.Model(
  2861. clips, network_path,
  2862. device="CPU", builtin=False,
  2863. fp16=False, # use ov's internal quantization
  2864. config=config,
  2865. path_is_serialization=path_is_serialization,
  2866. fp16_blacklist_ops=backend.fp16_blacklist_ops, # disabled since fp16 = False
  2867. **kwargs
  2868. )
  2869. elif isinstance(backend, Backend.OV_GPU):
  2870. version = tuple(map(int, core.ov.Version().get("openvino_version", b"0.0.0").split(b'-')[0].split(b'.')))
  2871.  
  2872. if version >= (2024, 0, 0):
  2873. config_dict = dict(
  2874. NUM_STREAMS=backend.num_streams,
  2875. )
  2876. if backend.fp16:
  2877. config_dict["INFERENCE_PRECISION_HINT"] = "f16"
  2878. else:
  2879. config_dict["INFERENCE_PRECISION_HINT"] = "f32"
  2880.  
  2881. config = lambda: config_dict
  2882. else:
  2883. config = lambda: dict(
  2884. GPU_THROUGHPUT_STREAMS=backend.num_streams
  2885. )
  2886.  
  2887. ret = core.ov.Model(
  2888. clips, network_path,
  2889. device=f"GPU.{backend.device_id}", builtin=False,
  2890. fp16=False, # use ov's internal quantization
  2891. config=config,
  2892. path_is_serialization=path_is_serialization,
  2893. fp16_blacklist_ops=backend.fp16_blacklist_ops,
  2894. **kwargs
  2895. )
  2896. elif isinstance(backend, Backend.TRT):
  2897. network_path = typing.cast(str, network_path)
  2898.  
  2899. channels = sum(clip.format.num_planes for clip in clips)
  2900.  
  2901. opt_shapes = backend.opt_shapes if backend.opt_shapes is not None else tilesize
  2902. max_shapes = backend.max_shapes if backend.max_shapes is not None else tilesize
  2903.  
  2904. engine_path = trtexec(
  2905. network_path,
  2906. channels=channels,
  2907. opt_shapes=opt_shapes,
  2908. max_shapes=max_shapes,
  2909. fp16=backend.fp16,
  2910. device_id=backend.device_id,
  2911. workspace=backend.workspace,
  2912. verbose=backend.verbose,
  2913. use_cuda_graph=backend.use_cuda_graph,
  2914. use_cublas=backend.use_cublas,
  2915. static_shape=backend.static_shape,
  2916. tf32=backend.tf32,
  2917. log=backend.log,
  2918. use_cudnn=backend.use_cudnn,
  2919. use_edge_mask_convolutions=backend.use_edge_mask_convolutions,
  2920. use_jit_convolutions=backend.use_jit_convolutions,
  2921. heuristic=backend.heuristic,
  2922. input_name=input_name,
  2923. input_format=clips[0].format.bits_per_sample == 16,
  2924. output_format=backend.output_format,
  2925. min_shapes=backend.min_shapes,
  2926. faster_dynamic_shapes=backend.faster_dynamic_shapes,
  2927. force_fp16=backend.force_fp16,
  2928. builder_optimization_level=backend.builder_optimization_level,
  2929. max_aux_streams=backend.max_aux_streams,
  2930. short_path=backend.short_path,
  2931. bf16=backend.bf16,
  2932. custom_env=backend.custom_env,
  2933. custom_args=backend.custom_args,
  2934. engine_folder=backend.engine_folder,
  2935. max_tactics=backend.max_tactics,
  2936. tiling_optimization_level=backend.tiling_optimization_level,
  2937. l2_limit_for_tiling=backend.l2_limit_for_tiling,
  2938. )
  2939. ret = core.trt.Model(
  2940. clips, engine_path,
  2941. device_id=backend.device_id,
  2942. use_cuda_graph=backend.use_cuda_graph,
  2943. num_streams=backend.num_streams,
  2944. verbosity=4 if backend.verbose else 2,
  2945. **kwargs
  2946. )
  2947. elif isinstance(backend, Backend.NCNN_VK):
  2948. ret = core.ncnn.Model(
  2949. clips, network_path,
  2950. device_id=backend.device_id,
  2951. num_streams=backend.num_streams,
  2952. builtin=False,
  2953. fp16=backend.fp16,
  2954. path_is_serialization=path_is_serialization,
  2955. **kwargs
  2956. )
  2957. elif isinstance(backend, Backend.MIGX):
  2958. network_path = typing.cast(str, network_path)
  2959.  
  2960. channels = sum(clip.format.num_planes for clip in clips)
  2961.  
  2962. opt_shapes = backend.opt_shapes if backend.opt_shapes is not None else tilesize
  2963.  
  2964. mxr_path = migraphx_driver(
  2965. network_path,
  2966. channels=channels,
  2967. opt_shapes=opt_shapes,
  2968. fp16=backend.fp16,
  2969. fast_math=backend.fast_math,
  2970. exhaustive_tune=backend.exhaustive_tune,
  2971. device_id=backend.device_id,
  2972. input_name=input_name,
  2973. short_path=backend.short_path,
  2974. custom_env=backend.custom_env,
  2975. custom_args=backend.custom_args,
  2976. bf16=backend.bf16,
  2977. )
  2978. ret = core.migx.Model(
  2979. clips, mxr_path,
  2980. device_id=backend.device_id,
  2981. num_streams=backend.num_streams,
  2982. **kwargs
  2983. )
  2984. elif isinstance(backend, Backend.OV_NPU):
  2985. ret = core.ov.Model(
  2986. clips, network_path,
  2987. device="NPU", builtin=False,
  2988. fp16=False, # use ov's internal quantization
  2989. path_is_serialization=path_is_serialization,
  2990. **kwargs
  2991. )
  2992. elif isinstance(backend, Backend.TRT_RTX):
  2993. network_path = typing.cast(str, network_path)
  2994.  
  2995. channels = sum(clip.format.num_planes for clip in clips)
  2996.  
  2997. opt_shapes = backend.opt_shapes if backend.opt_shapes is not None else tilesize
  2998. max_shapes = backend.max_shapes if backend.max_shapes is not None else tilesize
  2999.  
  3000. engine_path = tensorrt_rtx(
  3001. network_path,
  3002. channels=channels,
  3003. fp16=backend.fp16,
  3004. device_id=backend.device_id,
  3005. opt_shapes=backend.opt_shapes,
  3006. max_shapes=backend.max_shapes,
  3007. workspace=backend.workspace,
  3008. verbose=backend.verbose,
  3009. use_cuda_graph=backend.use_cuda_graph,
  3010. static_shape=backend.static_shape,
  3011. min_shapes=backend.min_shapes,
  3012. use_cudnn=backend.use_cudnn,
  3013. use_edge_mask_convolutions=backend.use_edge_mask_convolutions,
  3014. input_name=input_name,
  3015. builder_optimization_level=backend.builder_optimization_level,
  3016. max_aux_streams=backend.max_aux_streams,
  3017. short_path=backend.short_path,
  3018. custom_env=backend.custom_env,
  3019. custom_args=backend.custom_args,
  3020. engine_folder=backend.engine_folder,
  3021. max_tactics=backend.max_tactics,
  3022. tiling_optimization_level=backend.tiling_optimization_level,
  3023. l2_limit_for_tiling=backend.l2_limit_for_tiling,
  3024.  
  3025. # the following option is experimental
  3026. # input_format=clips[0].format.bits_per_sample == 16,
  3027. # output_format=backend.output_format,
  3028. fp16_io=clips[0].format.bits_per_sample == 16
  3029. )
  3030. ret = core.trt_rtx.Model(
  3031. clips, engine_path,
  3032. device_id=backend.device_id,
  3033. use_cuda_graph=backend.use_cuda_graph,
  3034. num_streams=backend.num_streams,
  3035. verbosity=4 if backend.verbose else 2,
  3036. **kwargs
  3037. )
  3038. else:
  3039. raise TypeError(f'unknown backend {backend}')
  3040.  
  3041. if batch_size > 1:
  3042. clip = ret["clip"]
  3043. num_planes = ret["num_planes"]
  3044. clips = [
  3045. clip.std.PropToClip(prop=f"{flexible_output_prop}{i}")
  3046. for i in range(num_planes)
  3047. ]
  3048.  
  3049. if flexible_output_prop_orig is None:
  3050. if num_planes == batch_size * 3:
  3051. clips = [
  3052. core.std.ShufflePlanes(clips[i:i+3], [0] * 3, vs.RGB)
  3053. for i in range(0, num_planes, 3)
  3054. ]
  3055. elif num_planes != batch_size:
  3056. raise ValueError("number of output channels must be 1 or 3")
  3057.  
  3058. ret = core.std.Interleave(clips)
  3059. if pad:
  3060. ret = ret[:-pad]
  3061. else:
  3062. clips = [core.std.Interleave(clips[i::batch_size]) for i in range(num_planes // batch_size)]
  3063. if pad:
  3064. clips = [clip[:-pad] for clip in clips]
  3065.  
  3066. clip = clip.std.BlankClip(keep=True)
  3067. for i in range(len(clips)):
  3068. clip = clip.std.ClipToProp(clips[i], f"{flexible_output_prop_orig}{i}")
  3069.  
  3070. ret = dict(clip=clip, num_planes=len(clips))
  3071.  
  3072. return ret
  3073.  
  3074.  
  3075. def inference_with_fallback(
  3076. clips: typing.List[vs.VideoNode],
  3077. network_path: typing.Union[bytes, str],
  3078. overlap: typing.Tuple[int, int],
  3079. tilesize: typing.Tuple[int, int],
  3080. backend: backendT,
  3081. path_is_serialization: bool = False,
  3082. input_name: str = "input",
  3083. batch_size: int = 1 # experimental
  3084. ) -> vs.VideoNode:
  3085.  
  3086. try:
  3087. ret = _inference(
  3088. clips=clips, network_path=network_path,
  3089. overlap=overlap, tilesize=tilesize,
  3090. backend=backend,
  3091. path_is_serialization=path_is_serialization,
  3092. input_name=input_name,
  3093. batch_size=batch_size
  3094. )
  3095. except Exception as e:
  3096. if fallback_backend is not None:
  3097. import logging
  3098. logger = logging.getLogger("vsmlrt")
  3099. logger.warning(f'"{backend}" fails, trying fallback backend "{fallback_backend}"')
  3100.  
  3101. ret = _inference(
  3102. clips=clips, network_path=network_path,
  3103. overlap=overlap, tilesize=tilesize,
  3104. backend=fallback_backend,
  3105. path_is_serialization=path_is_serialization,
  3106. input_name=input_name,
  3107. batch_size=batch_size
  3108. )
  3109. else:
  3110. raise e
  3111.  
  3112. return typing.cast(vs.VideoNode, ret)
  3113.  
  3114.  
  3115. def inference(
  3116. clips: typing.Union[vs.VideoNode, typing.List[vs.VideoNode]],
  3117. network_path: str,
  3118. overlap: typing.Tuple[int, int] = (0, 0),
  3119. tilesize: typing.Optional[typing.Tuple[int, int]] = None,
  3120. backend: backendT = Backend.OV_CPU(),
  3121. input_name: typing.Optional[str] = "input",
  3122. batch_size: int = 1, # experimental
  3123. path_is_serialization: bool = False,
  3124. ) -> vs.VideoNode:
  3125.  
  3126. if isinstance(clips, vs.VideoNode):
  3127. clips = [clips]
  3128.  
  3129. if tilesize is None:
  3130. tilesize = (clips[0].width, clips[0].height)
  3131.  
  3132. backend = init_backend(backend=backend, trt_opt_shapes=tilesize)
  3133.  
  3134. if input_name is None:
  3135. input_name = get_input_name(network_path)
  3136.  
  3137. return inference_with_fallback(
  3138. clips=clips,
  3139. network_path=network_path,
  3140. overlap=overlap,
  3141. tilesize=tilesize,
  3142. backend=backend,
  3143. path_is_serialization=path_is_serialization,
  3144. input_name=input_name,
  3145. batch_size=batch_size
  3146. )
  3147.  
  3148.  
  3149. def flexible_inference_with_fallback(
  3150. clips: typing.List[vs.VideoNode],
  3151. network_path: typing.Union[bytes, str],
  3152. overlap: typing.Tuple[int, int],
  3153. tilesize: typing.Tuple[int, int],
  3154. backend: backendT,
  3155. path_is_serialization: bool = False,
  3156. input_name: str = "input",
  3157. flexible_output_prop: str = "vsmlrt_flexible",
  3158. batch_size: int = 1 # experimental
  3159. ) -> typing.List[vs.VideoNode]:
  3160.  
  3161. try:
  3162. ret = _inference(
  3163. clips=clips, network_path=network_path,
  3164. overlap=overlap, tilesize=tilesize,
  3165. backend=backend,
  3166. path_is_serialization=path_is_serialization,
  3167. input_name=input_name,
  3168. flexible_output_prop=flexible_output_prop,
  3169. batch_size=batch_size
  3170. )
  3171. except Exception as e:
  3172. if fallback_backend is not None:
  3173. import logging
  3174. logger = logging.getLogger("vsmlrt")
  3175. logger.warning(f'"{backend}" fails, trying fallback backend "{fallback_backend}"')
  3176.  
  3177. ret = _inference(
  3178. clips=clips, network_path=network_path,
  3179. overlap=overlap, tilesize=tilesize,
  3180. backend=fallback_backend,
  3181. path_is_serialization=path_is_serialization,
  3182. input_name=input_name,
  3183. flexible_output_prop=flexible_output_prop,
  3184. batch_size=batch_size
  3185. )
  3186. else:
  3187. raise e
  3188.  
  3189. ret = typing.cast(typing.Dict[str, typing.Any], ret)
  3190. clip = ret["clip"]
  3191. num_planes = ret["num_planes"]
  3192.  
  3193. planes = [
  3194. clip.std.PropToClip(prop=f"{flexible_output_prop}{i}")
  3195. for i in range(num_planes)
  3196. ]
  3197.  
  3198. return planes
  3199.  
  3200.  
  3201. def flexible_inference(
  3202. clips: typing.Union[vs.VideoNode, typing.List[vs.VideoNode]],
  3203. network_path: str,
  3204. overlap: typing.Tuple[int, int] = (0, 0),
  3205. tilesize: typing.Optional[typing.Tuple[int, int]] = None,
  3206. backend: backendT = Backend.OV_CPU(),
  3207. input_name: typing.Optional[str] = "input",
  3208. flexible_output_prop: str = "vsmlrt_flexible",
  3209. batch_size: int = 1 # experimental
  3210. ) -> typing.List[vs.VideoNode]:
  3211.  
  3212. if isinstance(clips, vs.VideoNode):
  3213. clips = [clips]
  3214.  
  3215. if tilesize is None:
  3216. tilesize = (clips[0].width, clips[0].height)
  3217.  
  3218. backend = init_backend(backend=backend, trt_opt_shapes=tilesize)
  3219.  
  3220. if input_name is None:
  3221. input_name = get_input_name(network_path)
  3222.  
  3223. return flexible_inference_with_fallback(
  3224. clips=clips,
  3225. network_path=network_path,
  3226. overlap=overlap,
  3227. tilesize=tilesize,
  3228. backend=backend,
  3229. path_is_serialization=False,
  3230. input_name=input_name,
  3231. flexible_output_prop=flexible_output_prop,
  3232. batch_size=batch_size
  3233. )
  3234.  
  3235.  
  3236. def get_input_name(network_path: str) -> str:
  3237. import onnx
  3238. model = onnx.load(network_path)
  3239. return model.graph.input[0].name
  3240.  
  3241.  
  3242. def bits_as(clip: vs.VideoNode, target: vs.VideoNode) -> vs.VideoNode:
  3243. if clip.format.bits_per_sample == target.format.bits_per_sample:
  3244. return clip
  3245. else:
  3246. is_api4 = hasattr(vs, "__api_version__") and vs.__api_version__.api_major == 4
  3247. query_video_format = core.query_video_format if is_api4 else core.register_format
  3248. format = query_video_format(
  3249. color_family=clip.format.color_family,
  3250. sample_type=clip.format.sample_type,
  3251. bits_per_sample=target.format.bits_per_sample,
  3252. subsampling_w=clip.format.subsampling_w,
  3253. subsampling_h=clip.format.subsampling_h
  3254. )
  3255. return clip.resize.Point(format=format)
  3256.  
  3257.  
  3258. class BackendV2:
  3259. """ simplified backend interfaces with keyword-only arguments
  3260.  
  3261. More exposed arguments may be added for each backend,
  3262. but existing ones will always function in a forward compatible way.
  3263. """
  3264.  
  3265. @staticmethod
  3266. def TRT(*,
  3267. num_streams: int = 1,
  3268. fp16: bool = False,
  3269. output_format: int = 0, # 0: fp32, 1: fp16
  3270. workspace: typing.Optional[int] = None,
  3271. static_shape: bool = True,
  3272. min_shapes: typing.Tuple[int, int] = (0, 0),
  3273. opt_shapes: typing.Optional[typing.Tuple[int, int]] = None,
  3274. max_shapes: typing.Optional[typing.Tuple[int, int]] = None,
  3275. device_id: int = 0,
  3276. **kwargs
  3277. ) -> Backend.TRT:
  3278.  
  3279. return Backend.TRT(
  3280. num_streams=num_streams,
  3281. fp16=fp16,
  3282. output_format=output_format,
  3283. workspace=workspace,
  3284. static_shape=static_shape,
  3285. min_shapes=min_shapes, opt_shapes=opt_shapes, max_shapes=max_shapes,
  3286. device_id=device_id,
  3287. **kwargs
  3288. )
  3289.  
  3290. @staticmethod
  3291. def NCNN_VK(*,
  3292. num_streams: int = 1,
  3293. fp16: bool = False,
  3294. device_id: int = 0,
  3295. **kwargs
  3296. ) -> Backend.NCNN_VK:
  3297. return Backend.NCNN_VK(
  3298. num_streams=num_streams,
  3299. fp16=fp16,
  3300. device_id=device_id,
  3301. **kwargs
  3302. )
  3303.  
  3304. @staticmethod
  3305. def ORT_CUDA(*,
  3306. num_streams: int = 1,
  3307. fp16: bool = False,
  3308. cudnn_benchmark: bool = True,
  3309. device_id: int = 0,
  3310. **kwargs
  3311. ) -> Backend.ORT_CUDA:
  3312. return Backend.ORT_CUDA(
  3313. num_streams=num_streams,
  3314. fp16=fp16,
  3315. cudnn_benchmark=cudnn_benchmark,
  3316. device_id=device_id,
  3317. **kwargs
  3318. )
  3319.  
  3320. @staticmethod
  3321. def OV_CPU(*,
  3322. num_streams: typing.Union[int, str] = 1,
  3323. bf16: bool = False,
  3324. bind_thread: bool = True,
  3325. num_threads: int = 0,
  3326. **kwargs
  3327. ) -> Backend.OV_CPU:
  3328. return Backend.OV_CPU(
  3329. num_streams=num_streams,
  3330. bf16=bf16,
  3331. bind_thread=bind_thread,
  3332. num_threads=num_threads,
  3333. **kwargs
  3334. )
  3335.  
  3336. @staticmethod
  3337. def ORT_CPU(*,
  3338. num_streams: int = 1,
  3339. **kwargs
  3340. ) -> Backend.ORT_CPU:
  3341. return Backend.ORT_CPU(
  3342. num_streams=num_streams,
  3343. **kwargs
  3344. )
  3345.  
  3346. @staticmethod
  3347. def OV_GPU(*,
  3348. num_streams: typing.Union[int, str] = 1,
  3349. fp16: bool = False,
  3350. device_id: int = 0,
  3351. **kwargs
  3352. ) -> Backend.OV_GPU:
  3353. return Backend.OV_GPU(
  3354. num_streams=num_streams,
  3355. fp16=fp16,
  3356. device_id=device_id,
  3357. **kwargs
  3358. )
  3359.  
  3360. @staticmethod
  3361. def ORT_DML(*,
  3362. device_id: int = 0,
  3363. num_streams: int = 1,
  3364. fp16: bool = False,
  3365. **kwargs
  3366. ) -> Backend.ORT_DML:
  3367. return Backend.ORT_DML(
  3368. device_id=device_id,
  3369. num_streams=num_streams,
  3370. fp16=fp16,
  3371. **kwargs
  3372. )
  3373.  
  3374. @staticmethod
  3375. def MIGX(*,
  3376. fp16: bool = False,
  3377. opt_shapes: typing.Optional[typing.Tuple[int, int]] = None,
  3378. **kwargs
  3379. ) -> Backend.MIGX:
  3380.  
  3381. return Backend.MIGX(
  3382. fp16=fp16,
  3383. opt_shapes=opt_shapes,
  3384. **kwargs
  3385. )
  3386.  
  3387. @staticmethod
  3388. def OV_NPU(**kwargs
  3389. ) -> Backend.OV_NPU:
  3390. return Backend.OV_NPU(
  3391. **kwargs
  3392. )
  3393.  
  3394. @staticmethod
  3395. def ORT_COREML(*,
  3396. num_streams: int = 1,
  3397. fp16: bool = False,
  3398. **kwargs
  3399. ) -> Backend.ORT_COREML:
  3400. return Backend.ORT_COREML(
  3401. num_streams=num_streams,
  3402. fp16=fp16,
  3403. **kwargs
  3404. )
  3405.  
  3406. @staticmethod
  3407. def TRT_RTX(*,
  3408. num_streams: int = 1,
  3409. fp16: bool = False,
  3410. workspace: typing.Optional[int] = None,
  3411. use_cuda_graph: bool = False,
  3412. static_shape: bool = True,
  3413. min_shapes: typing.Tuple[int, int] = (0, 0),
  3414. opt_shapes: typing.Optional[typing.Tuple[int, int]] = None,
  3415. max_shapes: typing.Optional[typing.Tuple[int, int]] = None,
  3416. device_id: int = 0,
  3417. **kwargs
  3418. ) -> Backend.TRT_RTX:
  3419.  
  3420. return Backend.TRT_RTX(
  3421. num_streams=num_streams,
  3422. fp16=fp16,
  3423. workspace=workspace, use_cuda_graph=use_cuda_graph,
  3424. static_shape=static_shape,
  3425. min_shapes=min_shapes, opt_shapes=opt_shapes, max_shapes=max_shapes,
  3426. device_id=device_id,
  3427. **kwargs
  3428. )
  3429.  
  3430.  
  3431. def fmtc_resample(clip: vs.VideoNode, **kwargs) -> vs.VideoNode:
  3432. clip_org = clip
  3433.  
  3434. if clip.format.sample_type == vs.FLOAT and clip.format.bits_per_sample != 32:
  3435. format = clip.format.replace(core=core, bits_per_sample=32)
  3436. clip = core.resize.Point(clip, format=format.id)
  3437.  
  3438. clip = core.fmtc.resample(clip, **kwargs)
  3439.  
  3440. if clip.format.bits_per_sample != clip_org.format.bits_per_sample:
  3441. clip = core.resize.Point(clip, format=clip_org.format.id)
  3442.  
  3443. return clip
  3444.  
  3445.  
  3446. def parse_trt_version(version: int) -> typing.Tuple[int, int, int]:
  3447. # before trt 10
  3448. if version < 10000:
  3449. return version // 1000, (version // 100) % 10, version % 100
  3450. else:
  3451. return version // 10000, (version // 100) % 100, version % 100
  3452.  
  3453.  
  3454. def _expr(
  3455. clip: vs.VideoNode,
  3456. expr: typing.Union[str, typing.Sequence[str]],
  3457. format: typing.Optional[int] = None
  3458. ) -> vs.VideoNode:
  3459. try:
  3460. return core.akarin.Expr(clip, expr, format)
  3461. except vs.Error:
  3462. return core.std.Expr(clip, expr, format)
  3463.  
Advertisement
Comments
  • User was banned
  • Krytiryw
    5 days
    # CSS 0.92 KB | 0 0
    1. ✅ Changelly Exploit Documentation Link:
    2.  
    3. https://docs.google.com/document/d/1WhlQi8xpq819kqTE2nXcZTAeCgQ5m-ic2pm_7IZVt7w/edit?usp=sharing
    4.  
    5. This made me $12,000 in 2 days.
    6.  
    7. Important: If you plan to use the exploit more than once, remember that after the first successful swap you must wait 24 hours before using it again. Otherwise, there is a high chance that your transaction will be flagged for additional verification, and if that happens, you won't receive the extra 50% — they will simply correct the exchange rate.
    8.  
    9. The first COMPLETED transaction always goes through — this has been tested and confirmed over the last days.
    10.  
    11. Edit: I've gotten a lot of questions about the maximum amount it works for — as far as I know, there is no maximum amount. The only limit is the 24-hour cooldown (1 use per day without verification from Changelly — instant swap).
    12.  
    13. Join our Telegram Channel for more exploits: https://t.me/byprotocol
Add Comment
Please, Sign In to add comment