在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库

根据调查,普通人产生的1.2万亿张图像可以通过电话或数码相机捕获。这样的图像的存储,尤其是以高分辨率的原始格式,会占用大量内存。

JPEG指的是联合图像专家组,该组织于2017年庆祝成立25周年。JPEG标准指定了编解码器,该编解码器定义了如何将图像压缩为字节的位流并解压缩回图像。

JPEG编解码器的主要目的是最小化照片图像文件的文件大小。JPEG是一种有损压缩格式,这意味着它不存储原始图像的完整像素数据。JPEG的优点之一是,它可以微调所使用的压缩量。如果正确使用,这会产生良好的图像质量,同时还会使最小的合理文件大小成为可能。

JPEG压缩的关键组件如下:

  • 色彩空间转换可以分离亮度(Y)和色度(Cb,Cr)分量。Cb和Cr的下采样可以减小文件大小,而质量损失几乎没有引起注意,因为人的感知对这些图像分量不太敏感。这不是核心标准的一部分,但是定义为JFIF格式的一部分。
  • 基于块的离散余弦变换(DCT)允许以较低的频率压缩数据。
  • 量化允许对高频细节进行舍入系数。通常,可以丢失这些细节,因为人眼通常无法轻松地区分高频内容。
  • 逐行编码在部分解码位流后预览整个图像的低质量版本。

以下照片(图1)显示了JPEG压缩导致的图像质量损失。原始的蝴蝶图像为BMP格式(512×512,24位,769 kB,无压缩),然后以JPEG格式显示同一图像,质量压缩系数为50%,二次采样为4:2:0,24位,图片大小为33 KB。

图1a. 原始蝴蝶图像(无压缩,大小512×512,24位),769 KB。

图1b. 压缩蝴蝶图像(质量压缩系数50%,二次采样4:2:0,24位),33 KB。

JPEG如何运作

图2显示了JPEG编码器的一种常见配置。

图2.使用GPU CUDA软件和CPU的并行利用的JPEG编码过程图。

首先,JPEG编码以RGB彩色图像开始。

第二步涉及将颜色转换为代表亮度(亮度)的YCbCr颜色空间Y和代表色度(红色和蓝色投影)的Cb和Cr通道。然后,将Cb和Cr通道以预定因子(通常为2或3)进行下采样。下采样提供了压缩的第一阶段。

在下一阶段,将每个通道划分为8×8的块,并计算DCT,这是一种类似于傅立叶变换的频率空间变换。DCT本身是无损且可逆的,将一个8×8空间块转换为64个通道。

然后,对DCT系数进行量化,该过程是有损的并且包括第二压缩阶段。量化由JPEG质量参数控制,较低的质量设置对应于更严格的压缩,因此文件更小。

量化阈值特定于每个空间频率,并且已经过精心设计。对低频的压缩比对高频的压缩要少,因为人眼对大范围内的细微W误差比对高频信号的大小变化更敏感。

最后阶段是使用Huffman编码无损地压缩量化的DCT系数,并将其存储在JPEG文件中,如图2所示。

图3显示了NVIDIA GPU上的JPEG解码过程。

图3. JPEG解码过程采用了GPU CUDA和软件的并行利用。用于霍夫曼解码的混合(CPU / GPU)方法克服了串行过程的停顿。

JPEG解码过程从压缩的JPEG位流开始,并提取头信息。

然后,霍夫曼解码处理串行过程,因为从比特流中一次解码一个DCT系数。

下一步将解量化和逆DCT处理为8×8块。

上采样步骤处理YCbCr转换并产生解码的RGB图像。

NVIDIA通过基于CUDA技术构建的nvJPEG库加速了JPEG编解码器。我们开发了JPEG算法的完整并行实现。JPEG编码器和解码器工作流的典型GPU加速部分如图2和3所示。

新的JPEG硬件解码器

推出了NVIDIA A100 GPU,它具有专用的硬件JPEG解码器。以前,数据中心GPU上没有这样的硬件单元,JPEG解码是同时使用CPU和GPU的纯软件CUDA解决方案。

现在,硬件解码器与其余GPU同时运行,后者可以执行各种计算任务,例如图像分类,目标检测和图像分割。与NVIDIA Tesla V100相比,它以不止一种方式提供了显着的吞吐量提高,JPEG解码速度提高了4-8倍。

它通过CUDA工具包的一部分nvJPEG库公开。

nvJPEG库概述

nvJPEG是用于JPEG编解码器的GPU加速库。结合数据扩展和图像加载库NVIDIA DALI,它可以通过加速数据的解码和扩展来加速对图像分类模型的深度学习训练。A100包含5核硬件JPEG解码引擎。nvJPEG利用硬件后端来批量处理JPEG图像。

图4. JPEG硬件解码过程采用了硬件解码器和GPU CUDA软件的并行利用。硬件解码器独立于CUDA SM,因此可以同时使用软件GPU解码器。

通过选择具有nvjpegCreateExinit功能的硬件解码器,nvJPEG可提供基线JPEG解码和各种颜色转换格式(例如YUV 420、422、444)的加速。如图4所示,与纯CPU处理相比,这将使图像解码速度提高20倍。DALI的用户可以直接受益于这种硬件加速,因为nvJPEG是抽象的。

nvJPEG库支持以下操作:

  • nvJPEG编码
  • nvJPEG转码
  • nvJPEG解码(包括硬件(A100)支持)

该库支持以下JPEG选项:

  • 基线和渐进JPEG编码和解码,仅适用于A100的基线解码
  • 每像素8位
  • 霍夫曼比特流解码
  • 多达四个通道的JPEG位流
  • 8位和16位量化表
  • 以下三个色度通道Y,Cb,Cr(Y,U,V)的色度子采样:
  • 4:4:4
  • 4:2:2
  • 4:2:0
  • 4:4:0
  • 4:1:1
  • 4:1:0

该库具有以下功能:

  • 同时使用CPU和GPU的混合解码。
  • 库的输入在主机内存中,输出在GPU内存中。
  • 单张图像和批量图像解码。
  • 用户为设备提供的内存管理器和固定的主机内存分配。

绩效数字

对于本节中的性能图,使用了以下测试设置和GPU / CPU硬件:

  • NVIDIA V100 GPU:CPU – E5-2698 v4 @ 2GHz 3.6GHz Turbo(Broadwell)HT on GPU – Tesla V100-SXM2-16GB(GV100)1 16160 MiB 1 80 SM GPU视频时钟1312 Batch 128和单线程
  • NVIDIA A100 GPU CPU –铂金8168 @ 2GHz 3.7GHz Turbo(Skylake)HT on GPU – A100-SXM4-40GB(GA100)1 40557 MiB 1108 SM GPU视频时钟1095 Batch 128和单线程
  • CPU:CPU –铂金8168 @ 2GHz 3.7GHz Turbo(Skylake)HT在TurboJPEG解码上进行CPU测试
  • 图像数据集:2K FHD = 1920 x 1080 4K UHD = 3840 x 2160 CUDA Toolkit 11.0 CUDA驱动程序r450.24

接下来的两个图表显示了硬件JPEG解码器的解码速度。

图5.该图显示了A100上的硬件解码比V100上的CUDA混合解码所提高的速度。 

图6. V100上的混合解码器所需的CPU线程数,以跟上A100上的硬件解码器吞吐量。

通过将解码工作转移到硬件上,可以释放宝贵的CPU周期,以便更好地利用它们。

图7显示了编码加速。

图7a. 对于1920×1080(2K FHD),3840×2160(4K UHD)图像尺寸的CPU,CUDA(V100,A100)之间的JPEG基线编码吞吐量比较。

图7b. 对于1920×1080(2K FHD),3840×2160(4K UHD)图像尺寸的CPU,CUDA(V100,A100)之间的JPEG渐进编码吞吐量比较。

图像解码示例

这是使用nvJPEG库的图像解码示例。此示例显示了A100 GPU上硬件解码器的使用以及其他NVIDIA GPU的后端回退。

//

// The following code example shows how to use the nvJPEG library for JPEG image decoding.

//

// Libraries used

// nvJPEG decoding

int main()

{

...

// create nvJPEG decoder and decoder state

nvjpegDevAllocator_t dev_allocator = {&dev_malloc, &dev_free};

nvjpegPinnedAllocator_t pinned_allocator ={&host_malloc, &host_free};

// Selecting A100 Hardware decoder

nvjpegStatus_t status = nvjpegCreateEx(NVJPEG_BACKEND_HARDWARE,

&dev_allocator,

&pinned_allocator,

NVJPEG_FLAGS_DEFAULT,

&params.nvjpeg_handle);

params.hw_decode_available = true;

if( status == NVJPEG_STATUS_ARCH_MISMATCH) {

std::cout<<"Hardware Decoder not supported. Falling back to default backend"<<std::endl;

// GPU SW decoder selected

nvjpegCreateEx(NVJPEG_BACKEND_DEFAULT, &dev_allocator,

&pinned_allocator, NVJPEG_FLAGS_DEFAULT,

&params.nvjpeg_handle);

params.hw_decode_available = false;

}

// create JPEG decoder state

nvjpegJpegStateCreate(params.nvjpeg_handle, &params.nvjpeg_state)

// extract bitstream metadata to figure out whether a bitstream can be decoded

nvjpegJpegStreamParseHeader(params.nvjpeg_handle, (const unsigned char *)img_data[i].data(), img_len[i], params.jpeg_streams[0]);

// decode Batch images

nvjpegDecodeBatched(params.nvjpeg_handle, params.nvjpeg_state,

batched_bitstreams.data(),

batched_bitstreams_size.data(),

batched_output.data(), params.stream)

...

}

$ git clone https://github.com/NVIDIA/CUDALibrarySamples.git

$ cd nvJPEG/nvJPEG-Decoder/

$ mkdir build

$ cd build

$ cmake ..

$ make

// Running nvJPEG decoder

$ ./nvjpegDecoder -i ../input_images/ -o ~/tmp

Decoding images in directory: ../input_images/, total 12, batchsize 1

Processing: ../input_images/cat_baseline.jpg

Image is 3 channels.

Channel #0 size: 64 x 64

Channel #1 size: 64 x 64

Channel #2 size: 64 x 64

YUV 4:4:4 chroma subsampling

Done writing decoded image to file:/tmp/cat_baseline.bmp

Processing: ../input_images/img8.jpg

Image is 3 channels.

Channel #0 size: 480 x 640

Channel #1 size: 240 x 320

Channel #2 size: 240 x 320

YUV 4:2:0 chroma subsampling

Done writing decoded image to file:/tmp/img8.bmp

Processing: ../input_images/img5.jpg

Image is 3 channels.

Channel #0 size: 640 x 480

Channel #1 size: 320 x 240

Channel #2 size: 320 x 240

YUV 4:2:0 chroma subsampling

Done writing decoded image to file:/tmp/img5.bmp

Processing: ../input_images/img7.jpg

Image is 3 channels.

Channel #0 size: 480 x 640

Channel #1 size: 240 x 320

Channel #2 size: 240 x 320

YUV 4:2:0 chroma subsampling

Done writing decoded image to file:/tmp/img7.bmp

Processing: ../input_images/img2.jpg

Image is 3 channels.

Channel #0 size: 480 x 640

Channel #1 size: 240 x 320

Channel #2 size: 240 x 320

YUV 4:2:0 chroma subsampling

Done writing decoded image to file: /tmp/img2.bmp

Processing: ../input_images/img4.jpg

Image is 3 channels.

Channel #0 size: 640 x 426

Channel #1 size: 320 x 213

Channel #2 size: 320 x 213

YUV 4:2:0 chroma subsampling

Done writing decoded image to file:/tmp/img4.bmp

Processing: ../input_images/cat.jpg

Image is 3 channels.

Channel #0 size: 64 x 64

Channel #1 size: 64 x 64

Channel #2 size: 64 x 64

YUV 4:4:4 chroma subsampling

Done writing decoded image to file:/tmp/cat.bmp

Processing: ../input_images/cat_grayscale.jpg

Image is 1 channels.

Channel #0 size: 64 x 64

Grayscale JPEG

Done writing decoded image to file:/tmp/cat_grayscale.bmp

Processing: ../input_images/img1.jpg

Image is 3 channels.

Channel #0 size: 480 x 640

Channel #1 size: 240 x 320

Channel #2 size: 240 x 320

YUV 4:2:0 chroma subsampling

Done writing decoded image to file: /tmp/img1.bmp

Processing: ../input_images/img3.jpg

Image is 3 channels.

Channel #0 size: 640 x 426

Channel #1 size: 320 x 213

Channel #2 size: 320 x 213

YUV 4:2:0 chroma subsampling

Done writing decoded image to file:/tmp/img3.bmp

Processing: ../input_images/img9.jpg

Image is 3 channels.

Channel #0 size: 640 x 480

Channel #1 size: 320 x 240

Channel #2 size: 320 x 240

YUV 4:2:0 chroma subsampling

Done writing decoded image to file:/tmp/img9.bmp

Processing: ../input_images/img6.jpg

Image is 3 channels.

Channel #0 size: 640 x 480

Channel #1 size: 320 x 240

Channel #2 size: 320 x 240

YUV 4:2:0 chroma subsampling

Done writing decoded image to file:/tmp/img6.bmp

Total decoding time: 14.8286

Avg decoding time per image: 1.23571

Avg images per sec: 0.809248

Avg decoding time per batch: 1.23571

图像大小调整示例

图像调整大小和加水印示例根据客户端请求生成图像的缩放版本。图8显示了图像调整大小和加水印的典型工作流程。

图8.并行使用GPU软件和CUDA的图像大小调整和水印流水线。

下面的代码示例演示如何调整图像大小并在徽标图像上添加水印。

//

// The following code example shows how to resize images and watermark them with a logo image.

//

// Libraries used

// nvJPEG decoding, NPP Resize, NPP watermarking, nvJPEG encoding

int main()

{

...

// nvJPEG decoder

nReturnCode = nvjpegDecode(nvjpeg_handle, nvjpeg_decoder_state, dpImage, nSize, oformat, &imgDesc, NULL);

// NPP image resize

st = nppiResize_8u_C3R_Ctx(imgDesc.channel[0], imgDesc.pitch[0], srcSize,

srcRoi, imgResize.channel[0], imgResize.pitch[0], dstSize, dstRoi,

NPPI_INTER_LANCZOS, nppStreamCtx);

st = nppiResize_8u_C3R_Ctx(imgDescW.channel[0], imgDescW.pitch[0], srcSizeW,

srcRoiW,imgResizeW.channel[0], imgResizeW.pitch[0], dstSize, dstRoi,

NPPI_INTER_LANCZOS, nppStreamCtx);

// Alpha Blending watermarking

st = nppiAlphaCompC_8u_C3R_Ctx(imgResize.channel[0], imgResize.pitch[0],

255, imgResizeW.channel[0], imgResizeW.pitch[0], ALPHA_BLEND,

imgResize.channel[0], imgResize.pitch[0], dstSize, NPPI_OP_ALPHA_PLUS,

nppStreamCtx);

// nvJPEG encoding

nvjpegEncodeImage(nvjpeg_handle, nvjpeg_encoder_state, nvjpeg_encode_params,

&imgResize, iformat, dstSize.width, dstSize.height,NULL));

...

}

$ git clone https://github.com/NVIDIA/CUDALibrarySamples.git

$ cd nvJPEG/Image-Resize-WaterMark/

$ mkdir build

$ cd build

$ cmake ..

$ make

// Running Image resizer and watermarking

$ ./imageResizeWatermark -i ../input_images/ -o resize_images -q 85 -rw 512 -rh 512

在NVIDIA A100 GPU上利用硬件JPEG解码器和NVIDIA nvJPEG库的更多相关文章

  1. NVIDIA A100 GPUs上硬件JPEG解码器和NVIDIA nvJPEG库

    NVIDIA A100 GPUs上硬件JPEG解码器和NVIDIA nvJPEG库 Leveraging the Hardware JPEG Decoder and NVIDIA nvJPEG Lib ...

  2. 在NVIDIA A100 GPU中使用DALI和新的硬件JPEG解码器快速加载数据

    在NVIDIA A100 GPU中使用DALI和新的硬件JPEG解码器快速加载数据 如今,最流行的拍照设备智能手机可以捕获高达4K UHD的图像(3840×2160图像),原始数据超过25 MB.即使 ...

  3. NVIDIA GPU上的直接线性求解器

    NVIDIA GPU上的直接线性求解器 NVIDIA cuSOLVER库提供了密集且稀疏的直接线性求解器和本征求解器的集合,它们为计算机视觉,CFD,计算化学和线性优化应用程序提供了显着的加速.cuS ...

  4. 用NVIDIA A100 GPUs提高计算机视觉

    用NVIDIA A100 GPUs提高计算机视觉 Improving Computer Vision with NVIDIA A100 GPUs 在2020年英伟达GPU技术会议的主题演讲中,英伟达创 ...

  5. A100 GPU硬件架构

    A100 GPU硬件架构 NVIDIA GA100 GPU由多个GPU处理群集(GPC),纹理处理群集(TPC),流式多处理器(SM)和HBM2内存控制器组成. GA100 GPU的完整实现包括以下单 ...

  6. 舌尖上的硬件:CPU/GPU芯片制造解析(高清)(组图)

    一沙一世界,一树一菩提,我们这个世界的深邃全部蕴藏于一个个普通的平凡当中.小小的厨房所容纳的不仅仅是人们对味道的情感,更有推动整个世界前进的动力.要想理解我们的世界,有的时候只需要细细品味一下我们所喜 ...

  7. 利用nvidia-smi 管理和监控NVIDIA GPU设备

    NVIDIA系统管理界面介绍 原文来源:https://developer.nvidia.com/nvidia-system-management-interface NVIDIA系统管理界面(nvi ...

  8. NVIDIA GPU上的Tensor线性代数

    NVIDIA GPU上的Tensor线性代数 cuTENSOR库是同类中第一个GPU加速的张量线性代数库,提供张量收缩,归约和逐元素运算.cuTENSOR用于加速在深度学习训练和推理,计算机视觉,量子 ...

  9. NVIDIA GPU上的随机数生成

    NVIDIA GPU上的随机数生成 NVIDIA CUDA随机数生成库(cuRAND)提供高性能的GPU加速的随机数生成(RNG).cuRAND库使用NVIDIA GPU中提供的数百个处理器内核,将质 ...

随机推荐

  1. hdu1146

    题意:       题意最蛋疼,其实是水题,这个题意整的我wa了一个多小时,我就改改题意吧..有一条河,刚开始的时候在左岸有一条船,这条船最多能运n个货物,一趟的时间是t,有m个货物,每个货物有自己到 ...

  2. 从苏宁电器到卡巴斯基第15篇:我在苏宁电器当营业员 VII

    我们苹果的倒班制度 当年我在苏宁的时候,实行的是单休制度,而且只能选择在周一到周五其中的某一天,因为周六周日顾客比较多,是不允许休息的.尽管是单休,但并不表示我们在上班的时候每天都要完完整整地上八小时 ...

  3. hdu4920 矩阵乘法%3

    题意:      给你两个矩阵,让你求两矩阵的乘积,然后3取余.矩阵是n*n的,n<=800 思路:        如果什么都不考虑的话,矩阵的乘法是o(n^3)的,800*800*800 = ...

  4. Python脚本与Metasploit交互攻击

    Metasploit是一款强大的漏洞扫描和利用工具,编写Python脚本与Metasploit进行交互,可以自动化的扫描和利用漏洞. 相关文章:Metasploit框架的使用 在脚本中,我们首选需要利 ...

  5. Portswigger web security academy:OS command injection

    Portswigger web security academy:OS command injection 目录 Portswigger web security academy:OS command ...

  6. 【JavaScript】Leetcode每日一题-递增顺序搜索树

    [JavaScript]Leetcode每日一题-递增顺序搜索树 [题目描述] 给你一棵二叉搜索树,请你 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没 ...

  7. Django(7)url命名的作用

    前言 为什么我们url需要命名呢?url命名的作用是什么?我们先来看一个案例 案例 我们先在一个Django项目中,创建2个App,前台front和后台cms,然后在各自app下创建urls.py文件 ...

  8. OpenCV on Mac OSX: A step-by-step guide

    I'm using OpenCV for my 4th year design project and setting it up was a huge pain. I had to look thr ...

  9. [BUAA2021软工]结对第一阶段博客作业小结

    作业链接 结对项目-第一阶段 优秀作业推荐 本次博客作业虽然是简单总结,但是以下作业中都不乏有思考.有亮点的精彩内容,推荐给同学们阅读学习. 山鸣谷应,相得益彰--杰对项目-第一阶段总结 该组对于可能 ...

  10. 【BUAA软工】第一次团队作业——团队介绍

    项目 内容 班级:北航2020春软件工程 博客园班级博客 作业:团队介绍与采访往届团队 团队作业-团队介绍和采访 Part I 团队成员介绍 有图有真(jia)相 大名 个人介绍 角色意向 李PX 来 ...