在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. hdu4421 2-sat(枚举二进制每一位)

    题意:       给你一个数组b[][],在给你一些关系,问是否可以找到一个满足限制的a[], 关系如下(图片): 思路:       说到限制,而且还是两个两个之间的限制,那么很容易想到2-sat ...

  2. 基于C++简单Windows API的socket编程(阻塞模式)

    1. 概述:简单的基于Windows API的socket点对点聊天程序,为了方便初学者,本文代码均采用阻塞原理编写. 2. 代码样例 Server.cpp(服务端) #include <cst ...

  3. POJ3277 线段树段更新,点询问+二分离散化+暴力

    题意:       x轴上有一些矩形,问你这些矩形覆盖的面积和是多少. 思路:       首先范围很大,n很小,果断离散化,然后我们就是求出任意区间的最大值作为当前区间的高,最后在算一遍答案就行了, ...

  4. UVA11636复制粘贴

    #include<stdio.h> int main() {    int Cas = 1 ,n;    while(~scanf("%d" ,&n) & ...

  5. LA3135简单多路归并(优先队列)

    题意:       有N个任务,每个任务都有自己的时间间隔(就是每t秒请求执行一次)和任务id,这n个任务公用一个cpu,每次我们都执行时间靠前的,如果相同时间内有多个任务,就执行任务id小的,要求模 ...

  6. 【vue-09】axios

    [vue-09]axios 文档:Axios中文文档 官网 为什么要使用axios 功能特点: 支持发送ajax异步 支持在NodeJs中发送ajax请求. 支持Promise 支持拦截器请求和响应 ...

  7. opencv——机器视觉检测和计数

    引言 在机器视觉中,有时需要对产品进行检测和计数.其难点无非是对于产品的图像分割. 由于之前网购的维生素片,有时候忘了今天有没有吃过,就想对瓶子里的药片计数...在学习opencv以后,希望实现对于维 ...

  8. 通俗易懂的JS之Proxy

    与掘金文章同步,地址:https://juejin.cn/post/6964398933229436935 什么是代理模式 引入一个现实生活中的案例 我们作为用户需要去如何评估一个房子的好坏.如何办理 ...

  9. java基础——数组及其应用

    数组 数组时相同类型数据的有序集合 数组描述的时相同类型的若干数据,按照一个定的先后次序排列组合而成 其中,每一个数据成为数组元素,每个数组元素可以通过一个下标来访问他们 数组的声明&创建 首 ...

  10. Select Screen 0 with xrandr Ask QuestionScreen 0" here describes your whole virtual display made of these two outputs: eDP-1-

    Screen 0" here describes your whole virtual display made of these two outputs: eDP-1-1: physica ...