在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. 【ShardingSphere】ShardingSphere学习(三)-数据分片-分片

    分片键 分片算法 分片策略 SQL Hint 分片键 用于分片的数据库字段,是将数据库(表)水平拆分的关键字段.例:将订单表中的订单主键的尾数取模分片,则订单主键为分片字段. SQL中如果无分片字段, ...

  2. Xposed学习二:实现机制

    在上一篇我们学习了如何在AS中创建Xposed模块,本篇来分析下官方教程中redClock的实现原理.本系列文章基于version-51 public void handleLoadPackage(X ...

  3. UVA11021麻球繁衍

    题意:      有K只麻球,每只生存一天就会死亡,每只麻球在死之前有可能生下一些麻球,生i个麻球的概率是pi,问m天后所有的麻球都死亡的概率是多少? 思路:       涉及到全概率公式,因为麻球的 ...

  4. CVE-2018-8174(双杀漏洞)复现

    目录 CVE-2018-8174双杀漏洞复现一(不稳定) 下载payload MSF监听 CVE-2018-8174双杀漏洞复现二

  5. 【转】python SQLAlchemy

    数据库表是一个二维表,包含多行多列. 把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含id和name的user ...

  6. 『政善治』Postman工具 — 10、Postman中对Cookie的操作

    目录 1.往常的Cookie处理方式 2.Postman中的Cookie管理机制 3.自定义Cookie管理内容 在接口测试中,某些接口的调用,需要带入已有Cookie,比如有些接口需要登陆后才能访问 ...

  7. 关于MySQL参数,这些你要知道

    前言: 在前面一些文章中,经常能看到介绍某某参数的作用,可能有些小伙伴仍搞不清楚 MySQL 参数是啥.本篇文章我们来聊聊 MySQL 参数,学习下如何管理维护 MySQL 参数. 1.MySQL参数 ...

  8. Java_接口

    接口 接口中的方法全都是抽象方法,用来指定一些规则,让子类去重写.接口的作用主要体现在一下两点 1.指定规则2.利用这些规则给类做功能扩展 接口的定义和使用 接口使用interface关键字来定义,使 ...

  9. 墙裂推荐一波mysql学习资源

    在日常工作与学习中,无论是开发.运维.测试,还是架构师,数据库是一门必不可少的"必修课", 也是必备的涨薪神器.在互联网公司中,开源数据库用得比较多的当属 MySQL 了. 但my ...

  10. 进入除错模式!进入此模式后,将会出现更多的选项,分别是: · 以基本图形介面安装 CentOS 7 (使用标准显卡来设定安装流程图示); · 救援Centos系统; · 执行内存测试(Run a memory test);

    Centos 7.3 安装 0.0392017.07.14 20:12:09字数 1550阅读 985 Centos 7.3 基于 Red Hat 企业版的源代码的最新版本的 CentOS 7 在今年 ...