请问大批量图片处理速度的主要因素
Benson1997 opened this issue · 5 comments
大佬好,请问由于平常需要处理大量的扫描图片,请问影响整体处理速度的硬件,主要是CPU还是GPU,或者是内存也有关。能否大致介绍一下影响处理速度方面的因素。
或者能帮忙给点硬件升级建议。😊
(据说是从1070Ti升级到3系速度提升不多,4系好像要一万多了,哈哈。)
以下是我电脑配置:
——————————
处理器 英特尔 Core i7-8700K @ 3.70GHz 六核
主板 华硕 PRIME Z370-P ( Z370 芯片组 )——支持双显卡
内存 32 GB ( 英睿达 DDR4 2400MHz / 金士顿 DDR4 2400MHz )
主硬盘 西数 WDC WDS100T2B0C-00PXH0 ( 1 TB / 固态硬盘 )
主显卡 Nvidia GeForce GTX 1070 Ti ( 8 GB / 七彩虹 )
主要的瓶颈是 GPU。
我用的是 i7-8750H (6C12T) 和 GTX 1070,用 realesrgan-x4plus-anime 模型放大 1920x1080 的图片,拆分大小自动设定,不开 TTA 的话,放大一次大概要 12-15s,内存占用 600 MB,在放大期间 GPU 的占用是满的,CPU 除了刚开始放大的时候以外基本没有占用。
不过因为你在隔壁提到了图片压缩所以也简单分析一下好了,这个占用的是 CPU,对于刚才放大得到的 7680x4320 的图片:
- 用 cjpeg (mozjpeg) 压缩
cjpeg-static -outfile NUL -quality 80 -optimize -progressive input.png
:大约 3s,不过 cjpeg 只占用单核,所以大量处理的话可以同时开 CPU 核心数/线程数的编码器进行压缩。 - 用 cwebp (libwebp) 压缩
cwebp -q 80 -m * -sharp_yuv -mt input.png -o NUL
:-m
是用来选择压缩质量或速度的参数,-m 0
的话大概 4s,-m 6
大概 7s,另外虽然命令里用了-mt
但是实际测试下来 cwebp 也只占用单核,所以多开也是有效的。 - 用 avifenc (libavif) 压缩
avifenc --speed * --jobs all --depth 8 --yuv 420 --min 0 --max 63 -a end-usage=q -a cq-level=30 -a enable-chroma-deltaq=1 --autotiling --ignore-icc --ignore-xmp --ignore-exif input.png NUL
:--speed 10
大概 0.9s,--speed 6
大概 4s,--speed 4
大概 20s,--speed 0
大概 60s,avifenc 是会用多线程把 CPU 吃满的,多开意义不大。 - 用 cjxl (libjxl) 压缩
cjxl input.png NUL -q 80 -e *
:-e 1
大概 1.1s,-e 4
大概 1.2s,-e 6
大概 3s,-e 9
的内存占用跑到了 7 GB 我这里是没办法测试了(隔壁 avifenc 的内存占用最多也才 640 MB),另外 cjxl 也有多线程。
对于图片压缩来说,对速度影响最大的是控制速度的参数(也会影响压缩质量,参见国外 CDN 厂商 Cloudinary 的分析结果)。升级更多核心的 CPU 或许会有帮助,不过压缩图片的速度(一般来说你并不需要使用最慢的选项)与放大图片相比还是快很多,所以还是优先升级 GPU 比较好。
好的,非常感谢您的时间,讲解的非常详细了。
您说的多开,是多开主程序对吧。之前有多开过2-3个主程序同时处理,每个主程序处理一个文件夹,不过经常会出现其中某个程序在执行过程中报错。不知道是不是GPU被挤满了,所以报错。
还是多开的时候,应该把整个程序所在的文件夹复制多份,再单独从每个不同的文件夹中运行 realesrgan-gui.exe,这样是不是不容易出错一些。
现在能记录错误日志了,下次我提交一下错误信息。😁
我没有测试过多开 realesrgan-gui 的情况,并且也不会考虑在 GUI 里添加并行压缩图片或者是一边放大一边压缩前面的图片的功能(太复杂了)。放大图片本身会占满 GPU,所以多开也是没有意义的,甚至有爆显存的可能。
好的,明白了,realesrgan-gui 开一个运行就可以了。速度瓶颈主要是再GPU上,不纠结了,谢谢🤞
如果想要多开编码器的话(这就和 realesrgan-gui 没有关系了),我倒是写过类似的 Python 代码,可以参考:
import os
import subprocess
from concurrent.futures import ThreadPoolExecutor
def compress(inputPath: str):
outputPath = os.path.splitext(inputPath)[0] + '.webp'
p = subprocess.Popen(
(
'cwebp',
'-q', '80',
'-z', '9',
'-m', '6',
'-f', '10',
'-sharp_yuv',
'-mt',
inputPath,
'-o', outputPath,
),
)
p.wait()
with ThreadPoolExecutor(os.cpu_count()) as executor:
executor.map(
compress,
(os.path.join('dir', x) for x in os.listdir('dir'))
)