文章目录9.29.3 图像相关操作 9.3.6 压缩图片 9.4 机器学习 9.4.4 Otherfor ML9.5 Other
前言
平台或设备可能通过扩展机制支持未纳入核心标准的功能 。硬件供应商可以根据实际进行实现:
EXT扩展由标准工作组批准,但供应商支持是可选的 。表示这些扩展的字符串以开头 。厂商扩展具有特定的语法,通常仅在特定厂商的平台上运行 。它们的名称通常包含厂商公司名称的首字母缩写 。
此外,还可能存在私有或内部扩展,供应商可能不会公开,但可能提供给客户 。扩展可以针对平台或设备:
这两个函数将返回可用扩展的名称字符串列表 。在使用扩展时有一些注意事项:
以下表格显示了在888 设备上支持的 KHR 和厂商扩展 。这些扩展的详细文档可在SDK 中找到,可以从 QTI 开发者网络网站()下载 。
在接下来的几节中 , 将跳过 KHR 扩展 , 并提供GPU 可用的厂商扩展的高级概述 。
9.1 OS-
这一部分介绍的一些扩展可能依赖于操作系统及其底层设计 , 这可能会发生变化 。检查SDK 开发文档以获取扩展详细信息 。本文档其他部分介绍的扩展将被跳过 。例如,零拷贝扩展的详细信息在第 7.4 节中 。
9.1.1hint ()
该扩展允许应用程序在上下文中请求所需设备的性能级别 。更高的性能意味着设备上的频率更高 。该扩展支持三个性能提示级别 , 包括高、正常和低,分别使用标志 OM、QCOM 和 M 。
使用这个扩展的两种方式:
9.1.2hint for(t)
(内核优先级)该扩展允许应用程序指定要提交到上下文中的设备的已入队内核的期望优先级 。与性能提示标志一样 , 它定义了三个优先级级别:
这个提示应该在创建上下文时使用作为上下文属性提供 。
9.1.3queue (ueues)
内核入队函数调用 el 是关键且要求较多的函数 , 它将内核分派到 GPU 硬件,因为它要求应用程序配置和验证许多内核参数 , 如全局工作大小、工作组大小、事件依赖性等 。对于需要重复处理的内核,比如视频处理应用,在每帧中重复执行相同内核的情况下,开发者可以最小化(反复)设置参数的开销 。
这个扩展不适用于(KEK)功能或。的工作组一直在进行努力,以标准化一个支持类似功能但更通用的 KHR 扩展 。9.1.4 ntext
此扩展允许应用程序创建所谓的受保护的上下文 。在受保护的上下文上创建的命令队列也被隐式地视为受保护的 。受保护的上下文使得可以使用特定GPU 上可用的内容保护功能 。此功能的主要目的是将内存分隔为受保护和非受保护的区域 , 并防止从受保护区域复制数据到非受保护区域 。要使用此功能 , 必须创建一个带有 _QCOM 属性的上下文:
【Chart 9 Adreno GPU的 OpenCL 扩展】cl_context_properties properties[] = {CL_CONTEXT_PROTECTED_QCOM, 1, 0};protected_context = clCreateContext(properties, 1, &device_id, NULL, NULL, &err);
一旦使用上述上下文创建了受保护的命令队列,在整个应用程序中使用了它:
protected_queue = clCreateCommandQueue(protected_context, device_id, 0, &err);
在上创建受保护的内存对象基本上有两种方式:
在这两种情况下 , 缓冲区都被视为受保护的内存对象 。在应用程序中,如果要将一个或多个受保护的内存对象作为参数入队到内核中,只能使用受保护的命令队列 。
9.1.5
在中 , 图像对象是一种不透明的数据结构,由API 中定义的函数进行管理 。开发人员无法访问图像对象中存储数据的底层细节 。与可以使用指针直接访问的缓冲区对象不同,内核中必须使用像 / 这样的内置图像读取和写入函数来访问图像数据 。
在某些情况下,开发人员可能希望在C 语言中以原始指针的形式访问图像数据,而不是使用内置的图像读写函数 。这个扩展可以在以下用例中发挥作用:
使用这个扩展,可以通过以下函数从现有的图像对象创建一个新的原始缓冲对象:
cl_mem clCreateBufferFromImageQCOM(cl_mem image, cl_mem_flags flags, cl_int *errcode_ret)
其中 , 图像是具有一些限制的有效图像 。对于图像类型、布局以及并发读/写访问 , 有一些要求:
数据布局:为了正确访问返回缓冲区中的像素数据,客户端必须使用 QCOM 查询父图像的两个参数:读写并发性支持:9.1.6
这个扩展提供了在 GPU的快速访问片上全局内存(以下简称片上全局内存)中创建缓冲区和图像的功能 。一旦创建了这些对象,它们可以在内核中像常规全局内存对象一样使用 。
如果存在,此扩展进一步允许从在片上全局内存中创建的缓冲区创建平面图像 。
默认情况下,在内核退出后,片上全局内存的内容不会被保留 。然而,应用程序可以利用ueues扩展使片上全局内存在两个或多个内核之间传递数据 。片上全局内存的内容将在记录的入队期间始终有效 。因此 , 应用程序可以使用片上全局内存将一个内核的输出链接到下一个内核的输入,只要这些内核是同一记录的一部分 。片上全局内存,在同一记录的不同入队之间不会被保留 。记录中的第一个内核必须将片上全局内存视为未初始化 。
通过在片上全局内存中分配缓冲区和图像,而不是全局分配,应用程序可以实现功耗和性能的改进 。一个例子是在内核流水线中使用片上全局内存作为中间缓冲区 。
请参考SDK中的扩展文档和演示片上全局内存用法的示例 。
9.1.7
GPUs支持的两个供应商扩展 , 和mage(都在第9.3节中介绍),允许开发人员创建可在内核中使用的平面和压缩图像 。
此扩展,,通过启用应用程序查询图像属性,如图像大小、图像元素大小、行间距、切片间距和基于图像格式和图像描述符的对齐方式,来补充上述扩展 。不需要创建图像即可查询这些属性 。
该扩展接受传统的RGBA图像和非传统图像 , 如NV12、TP10、MIPI打包、Bayer模式、平铺和压缩图像 。
请参考SDK中的扩展文档和演示用法的示例 。
9.2
2.0引入了一个名为的KHR核心扩展,通过这个扩展,引入了一系列子组函数,以促进子组内工作项之间的数据共享,从而为协作工作项提供了细粒度的协同工作 。如果没有这个功能,工作项之间的数据共享必须依赖于本地或全局内存,并且还需要昂贵的工作组屏障同步以确保数据一致性 。
在 3.0中,这个扩展中的许多子组函数已经被采纳为核心特性,比如、、sive_、sive_ , 其中可以是add、min或max 。
GPU有几个与子组相关的扩展,提供额外的功能,详见以下各节 。
9.2.1size (wave size)
GPU通常支持两种不同的子组大小,即半波大小和全波大小 。一个内核可以在两种模式下运行,可能导致不同的性能表现 。编译器根据预测内核性能的启发式方法选择最佳的子组大小 。在某些情况下,应用程序可能通过使用此扩展覆盖编译器的选择来获得更好的结果 。该扩展提供了一个内核属性,使应用程序能够指定首选的子组大小 。
要使用此扩展,必须在程序中启用# , 并设置波大小属性 。
#pragma OPENCL EXTENSION cl_qcom_reqd_sub_group_size: enable__attribute__((qcom_reqd_sub_group_size("half")))kernel void half_sub_group_kernel(...){ ... }__attribute__((qcom_reqd_sub_group_size("full")))kernel void full_sub_group_kernel(...){ ... }
以下是一些建议:
9.2.2
GPUs支持多个子组洗牌函数,如ffle,如表9-2所示 。这些洗牌函数的目标是将中的数据从当前工作项传输到目标工作项 。关键是确定,即子组中的目标工作项 。这个变量取决于一些参数,如下所示:
当计算得到的超出范围时的行为:宽度模式:
为了使用洗牌函数,将添加到内核中:
#pragma OPENCL EXTENSION cl_qcom_subgroup_shuffle: enable
该扩展支持的数据类型包括 uchar、char、、short、uint、int、ulong、long、float 和 half(如果支持 ) 。不支持矢量 。
一些建议:
工作项数量的要求:对的要求:9.3 图像相关操作
GPU内置硬件模块 , 加速常见的滤波操作,包括卷积、 Box 、SAD(绝对差之和)和SSD(平方差之和)等 。使用这些模块可能比使用通用的内核语言具有更好的性能或更低的功耗 。
9.3.1 卷积
卷积滤波操作将图像样本值的矩阵与滤波权重的矩阵相乘,并将结果求和以生成输出值 。有关该扩展的文档和示例,请参考SDK 。该扩展要求应用程序创建一个特殊的图像对象,并提供对权重矩阵的详细描述 , 如以下示例所示:
weight_img_desc.image_desc.image_type =CL_MEM_OBJECT_WEIGHT_IMAGE_QCOM;weight_img_desc.image_desc.image_width = filter_size_x;weight_img_desc.image_desc.image_height = filter_size_yweight_img_desc.image_desc.image_array_size = num_phases;weight_img_desc.image_desc.image_row_pitch = 0; // must set to zeroweight_img_desc.image_desc.image_slice_pitch = 0; // must set to zeroweight_img_desc.weight_desc.center_coord_x = center_coord_x; weight_img_desc.weight_desc.center_coord_y = center_coord_y;// specify separable filter. Default (flags=0) is 2D convolution filterweight_img_desc.weight_desc.flags = CL_WEIGHT_IMAGE_SEPARABLE_QCOM;
权重矩阵描述符包含进行操作所需的所有信息 。除了常规的图像属性,如宽度和高度,还需要权重矩阵的中心坐标以及卷积的类型,即它是否是可分离的 。在此扩展中,支持两种类型的卷积滤波器 , 即2D卷积滤波器和可分离卷积滤波器 。
对于 2D 卷积滤波:
可分离卷积核:
Table 9-2
n and
image type flags
和。权重图像只支持从内核进行读访问
使用进行查询,将图像类型设置为。
2D 卷积核;
=*。这要求这两个值( 和 )都必须是2的幂 。每个滤波阶段的权重值都组织成一个2D切片,大小为 ( * ) 。
可分离卷积核:
== (必须是2的幂) 。每个滤波阶段的1D水平和1D垂直滤波器的权重都组织成一个2D切片,切片高度为2,切片宽度为max(, ) 。
如果大于1,则权重切片 。
权重切片必须组织成一个2D数组,其切片数量等于 。在内建执行期间,相位值是根据滤波器中心点的坐标相对于像素中心的亚像素偏移来计算的 。
卷积函数限制:
9.2.3 Box
Box是一种线性操作,它取源图像上由 box覆盖的空间区域内的像素的平均值 。Box由 (, ) 和 box中心位置的坐标指定 。在数学上,以坐标 (x, y) 为中心的 box产生的像素的线性平均计算如下:
box_filter(x, y) = sum(weight(i, j) * pix(i, j)) / (box_width * box_height)
其中,(i, j) 是由 box覆盖的像素的坐标 。重要的是要注意,有些像素可能只被 box部分覆盖 。因此,(i, j) 根据像素(i, j)被 box覆盖的程度进行调整 。例如,如果像素被 50% 覆盖,权重将为 0.5 。图 9-3 显示了将 2x2 box应用于 5x6 图像的示例 。权重由内置硬件自动计算 。
由于Box的中心坐标为 (2, 2),有九个像素被该滤波器覆盖 。根据滤波器覆盖的像素,权重如下调整:
W(0, 0) = 0.25W(1, 0) = 0.5 W(2, 0) = 0.25W(0, 1) = 0.5W(1, 1) = 1W(2, 1) = 0.5W(0, 2) = 0.25W(1, 2) = 0.5 W(2, 1) = 0.25
图9-4展示了一个3x3的滤波器,其中所有来自源图像的像素都被完全覆盖 。因此 , 对于这种滤波,每个像素的权重是相等的 。
内建的 Box函数定义如下:
float4 qcom_box_filter_imagef(image2d_t image, sampler_t sampler, float2 coord, const qcom_box_size_t box_size);
限制:
-输入 image、 和必须对执行 ef 函数的工作组内的所有工作项保持一致 。
9.3.3 绝对值差之和(SAD)和平方差之和(SSD)
块匹配(Block )操作测量目标图像内的块与参考图像内的参考块之间的相关性(或相似性) 。有两个用于测量两个图像块之间相关性的误差度量:绝对差值和平方差值 。
假设有两个候选块 A 和 B,我们想知道哪一个与块 R 最匹配 。通过计算 A 和 R 之间的绝对差值和 B 和 R 之间的绝对差值,我们可以选择导致最小误差或最小绝对差值的块 。这可以推广到在一组 N 个目标块中搜索参考块 R 的最小绝对差值 。这两个函数的定义如下:
float4 qcom_block_match_sadf(image2d_t target_image, sampler_t sampler, float2 coord, uint2 region, image2d_t reference_image, uint2 reference_coord);float4 qcom_block_match_ssdf(image2d_t target_image, sampler_t sampler, float2 coord,uint2 region, image2d_t reference_image, uint2 reference_coord);
这两个函数与本节中的卷积和 Box操作有类似的要求 。此外,指定图像上目标块和参考块大小的和必须是整数 。
9.3.4
除了标准中定义的过滤器模式(例如或 )之外,新的GPU 中添加了一种称为 OM 的过滤器模式,允许开发人员使用硬件加速的双三次插值 。要使用此功能,需要在内核中使用名为的。使用 BIC 过滤器模式时 , 图像读取函数返回图像元素的 4x4 方格的加权平均值 。给定 2D 图像的输入坐标 (x, y),可以如下获取 4x4 方格:
x0 = (int) floor(x - 1.5f);y0 = (int) floor(y - 1.5f);x1 = x0 + 1;y1 = y0 + 1;x2 = x1 + 1;y2 = y1 + 1;x3 = x2 + 1;y3 = y2 + 1;a = frac(x - 0.5f); b = frac(y - 0.5f);
中 frac(x) 表示 x 的小数部分,计算方式为 x - floor(x) 。然后,权重计算如下:
w_u0 = - 0.5f * a + 1.0f * (a * a) - 0.5f * (a * a * a);w_u1 = 1.0f - 2.5f * (a * a) +1.5f * (a * a * a);w_u2 = 0.5f * a + 2.0f * (a * a) - 1.5f * (a * a * a);w_u3 = - 0.5f * (a * a) + 0.5f * (a * a * a);w_v0 = - 0.5f * b + 1.0f * (b * b) - 0.5f * (b * b * b);w_v1 = 1.0f - 2.5f * (b * b) + 1.5f * (b * b * b);w_v2 = 0.5f * b + 2.0f * (b * b) - 1.5f * (b * b * b);w_v3 = -0.5f * (b * b) + 0.5f * (b * b * b);
计算得到的图像元素值如下:
refOut =(t00*w_v0 + t01*w_v1+ t02*w_v2 + t03*w_v3) * w_u0 +(t10*w_v0 + t11*w_v1+ t12*w_v2 + t13*w_v3) * w_u1 +(t20*w_v0 + t21*w_v1+ t22*w_v2 + t23*w_v3) * w_u2 +(t30*w_v0 + t31*w_v1+ t32*w_v2 + t33*w_v3) * w_u3;
txy是(x,y)位置的像素值,如果上述方程中选择的任何 txy 引用图像之外的位置,则使用边框颜色作为 txy 的颜色值 。
注意,built-in 的双三次硬件加速具有有限的精度 。因此,在使用它时,检查您的应用程序的精度要求非常重要 。有关更多详细信息,请参阅SDK 中关于 ic 的文档和示例 。
9.3.5 (强大的)图像矢量化操作
在标准的中 , 像 / 等的图像读取/写入函数只能在单个操作中读取或写入一个像素(根据图像格式的不同 , 可能是一个或多个分量) 。_ops 扩展引入了一组新的内建函数,允许以单个操作读取和写入一组图像元素 。它们允许应用程序跨多个图像元素读取或写入单个分量 。因此,它们被称为矢量图像操作,可以提供潜在的性能增益以及开发的便利性 。
这些内建函数适用于一系列输入图像格式 , 它们的名称指示了返回值的数据类型以及它们的访问模式 。以下是一些矢量图像读取内建函数的示例:
9.3.5.1 2x2 read
操作从输入图像中读取形成一个 2x2 矢量的四个元素:
float4 qcom_read_imagef_2x2(image2D_t image, sampler_t sampler, float2 coord, int compid);half4 qcom_read_imageh_2x2(image2D_t image, sampler_t sampler, float2 coord, int compid);uint4 qcom_read_imageui_2x2(image2D_t image, sampler_t sampler, float2 coord, int compid);int4 qcom_read_imagei_2x2(image2D_t image, sampler_t sampler, float2 coord, int compid);
coord 指定的基准点是此向量的左上角 。[0] 是左下角的元素 。四个输出元素按逆时针顺序从 2x2 向量的 [0] 开始排序 。具体而言,[1] 是右下角,[2] 是右上角,[3] 是左上角(基准点),如图9-5所示 。
9.3.5.2 4x1 read
操作从输入图像中以 4x1 向量的形式读取四个元素:
float4 qcom_read_imagef_4x1(image2d_t image, sampler_t sampler, float2 coord, int compid);half4 qcom_read_imageh_4x1(image2d_t image, sampler_t sampler, float2 coord, int compid);uint4 qcom_read_imageui_4x1(image2d_t image, sampler_t sampler, float2 coord, int compid);int4 qcom_read_imagei_4x1(image2d_t image, sampler_t sampler, float2 coord, int compid);
将 [0] 表示为位于基准点 处的元素 。四个输出元素按照从左到右的顺序排列,从 4x1 向量的 [0] 开始 。具体而言,[0] 是最左侧的元素,然后是 [1]、[2] 和 [3] 。
文章插图
9.3.5.3 image write
GPU 支持一组新的内建矢量图像写入函数,其命名规范为 ######## 。函数名称明确指定了它支持的图像格式、矢量格式以及目标图像的格式和平面 。这些图像写入函数有许多变种 。以下是一些示例:
qcom_write_imagefv_2x1_n8n00(image2d_t image, int2 coord, float color[2])qcom_write_imagefv_2x1_n8n01(image2d_t image, int2 coord, float2 color[2])qcom_write_imagefv_2x1_n10p00(image2d_t image, int2 coord, float color[2])qcom_write_imagehv_3x1_n10t00(image2d_t image, int2 coord, half color[3])qcom_write_imageuiv_4x1_u10m00(image2d_t image, int2 coord, uint color[4])
某些函数需要特定的图像格式 , 如和。Y only 和 UV only 图像是 multi-plane的-plane衍生物 。它们可以通过使用扩展来创建 。(我没读懂,不好解释)
重要的是要理解这些函数必须与支持的图像类型和数据类型一起使用 。否则,返回值将是未定义的 。例如,用于读取浮点数的和函数仅支持使用格式如 、、 和创建的图像 。在 YUV 格式的图像中,矢量读取和写入图像有一些特殊规则:
在 U 或 V 平面进行的 2x2 读取将返回四个不同的 U 或 V 值 。例如,参考以下的 4x4 图像:
Note:
YUV 颜色编码采用的是 明亮度 和 色度 来指定像素的颜色 。其中,Y 表示明亮度(、Luma),而 U 和 V 表示色度(、) 。而色度又定义了颜色的两个方面:色调和饱和度 。
使用 YUV 颜色编码表示一幅图像 , 它应该下面这样的:
和 RGB 表示图像类似,每个像素点都包含 Y、U、V 分量 。但是它的 Y 和 UV 分量是可以分离的,如果没有 UV 分量一样可以显示完整的图像,只不过是黑白的 。
对于 YUV 图像来说,并不是每个像素点都需要包含了 Y、U、V 三个分量,根据不同的采样格式,可以每个 Y 分量都对应自己的 UV 分量 , 也可以几个 Y 分量共用 UV 分量 。
9.3.6 压缩图片
一个名为mage的扩展在 GPU中得到支持,该扩展允许以设计的专有压缩格式读取和写入图像 。除了节省内存带宽外,它还可能降低功耗和能耗,这对许多相机和视频用例特别有用,因为它们通常对数据需求很高 。要使用该扩展,主机必须使用表9-4中的函数查询格式的可用性 , 以及通道和数据类型的支持信息,因为它们在不同的 GPU上可能会有所不同 。使用压缩图像格式的方法与常规图像格式类似:
使用压缩格式的典型用例和工作流程是让GPU读取SOC中其他模块(例如相机模块)生成的压缩数据 。这通常与零拷贝技术相结合(即使用ION内存或本地缓冲区技术) 。表9-4显示了这两种方法的步骤,它们非常相似,只是一些标志和枚举类型有所不同 。
Table 9-4 Steps to useimage
ION
// 查询支持的格式errcode = clGetSupportedImageFormats(context, CL_MEM_READ_ONLY | CL_MEM_COMPRESSED_IMAGE_QCOM, CL_MEM_OBJECT_IMAGE2D, num_format_list_entries, format_list, &num_reported_image_formats);// 创建一个缓冲区来保存图像数据cl_mem_ion_host_ptrcompressed_ionmem = {0}; // Initialize ION buffer attributes compressed_ionmem.ext_host_ptr.allocation_type = CL_MEM_ION_HOST_PTR_QCOM;compressed_ionmem.ext_host_ptr.host_cache_policy = CL_MEM_HOST_UNCACHED_QCOM; compressed_ionmem.ion_filedesc = ion_info_fd.file_descriptor; // file descriptor for ION compressed_ionmem.ion_hostptr = ion_info.host_virtual_address; // hostptr returned by ION// 创建一个可供应用程序使用的图像对象cl_image_format image_format = {0}; cl_image_desc image_desc = {0}; cl_int errcode = 0; // Set image format image_format->image_channel_order = CL_QCOM_COMPRESSED_RGBA; image_format- >image_channel_data_type = CL_UNORM_INT8; // Set image parameters image_desc->image_width = 128; image_desc->image_height = 256; image_desc->image_row_pitch = 0; // must be 0 for compressed images image_desc->image_slice_pitch = 0; // Create a compressed image compressed_rbga_image = clCreateImage (context, CL_MEM_EXT_HOST_PTR_QCOM CL_MEM_READ_ONLY, image_format, image_desc, (void*)compressed_ionmem, &errcode);
// 查询支持的格式errcode = clGetSupportedImageFormats(context, CL_MEM_READ_ONLY | CL_MEM_COMPRESSED_IMAGE_QCOM, CL_MEM_OBJECT_IMAGE2D, num_format_list_entries, format_list, &num_reported_image_formats);// 创建一个缓冲区来保存图像数据cl_mem_android_native_buffer_host_ptr compressed_ANBmem = {0};GraphicBuffer *gb; // previously created the hostptr to a native buffer and gb is an Android GraphicBuffercompressed_ANBmem.ext_host_ptr.allocation_type = CL_MEM_ANDROID_NATIVE_BUFFER_HOST_PTR_QCOM; compressed_ANBmem.ext_host_ptr.host_cache_policy = CL_MEM_HOST_WRITEBACK_QCOM; compressed_ANBmem.anb_ptr = gb->getNativeBuffer();// 创建一个可供应用程序使用的图像对象cl_image_format image_format = {0};cl_image_desc image_desc = {0};cl_int errcode = 0;// Set image formatimage_format->image_channel_order = CL_QCOM_COMPRESSED_RGBA;image_format->image_channel_data_type = CL_UNORM_INT8;// Set image parametersimage_desc->image_width = 128;image_desc->image_height = 256;image_desc->image_row_pitch = 0; // always 0 for compressed images image_desc->image_slice_pitch = 0;// Create a compressed imageimages compressed_rbga_image = clCreateImage(context, CL_MEM_EXT_HOST_PTR_QCOM | CL_MEM_READ_ONLY, image_format, image_desc, (void*)compressed_ANBmem &errcode);
GPU上的可以解码和读取压缩图像,并将其写入另一个具有相同压缩格式的图像 。然而,压缩图像只能在内核内部进行读取或写入 。不支持压缩图像的原地读/写功能,即 。
9.4 机器学习 9.4.1 SNPE/QNN(神经网络处理引擎)
神经处理软件开发工具包(SNPE/QNN)是边缘计算中机器学习工作负载的成熟解决方案 。这个专有的、闭源的软件开发工具包取得了巨大的成功 。它为客户提供了一套庞大的工具和软件开发工具包,通过使用上的所有可用计算设备,包括CPU、GPU和DSP,来加速神经网络 。由于其高商业质量,制造商和开发人员已经采用了神经处理SDK 。
一些高级开发人员仍然更喜欢专门在 GPU上运行其机器学习工作负载 。他们可以利用最近发布的高通ML SDK,以实现在 GPU上的定制、灵活性和加速 。(自夸哈 , 不用读)
9.4.2ML SDK forGPU
开发人员可以通过扩展加速许多常见的机器学习操作 。高通优化的操作可以提供显著的性能优势 。它们支持推理和训练 。请参考MK SDK获取文档和示例 。有关更多详细信息 , 请查看博客:《在 GPU上使用进行机器学习加速 - 高通开发者网络》 。以下是SDK的一些要素:
9.4.3(TVM) and the
最近,TVM,一个为深度学习工作负载提供支持的知名且非常活跃的开源编译器框架,已经添加了对的扩展的支持 。这降低了开发人员使用该SDK的门槛,并有助于在 GPU上快速生成和原型化运行的ML网络 。
9.4.3.1 TVM
TVM能够自动生成针对给定的机器学习操作的多个内核实现 。它可以使用基于机器学习的调整方法 , 从庞大的搜索空间中找到性能最佳的内核 。TVM可以在机器学习模型上进行操作级别和图级别的优化,生成适用于各种硬件模块的高性能内核实现 。而且 , 由于TVM是开源的 , 它得到了一个庞大而活跃的社区的支持 , 该社区的成员来自工业界和学术界 。
9.4.3.2 How TVM works with the
TVM社区引入了BYOC(Bring Your Own Code)作为一种将供应商加速库(如)中的高性能内核嵌入到TVM生成的主要代码中的方法 。因此,我们正在利用BYOC来集成扩展到TVM,以实现端到端的解决方案 。
尽管扩展功能强大,但其专有的API带有一定的学习曲线 。与单独使用SDK相比,TVM和的集成更为简单 。通过这种集成,开发人员无需理解规范、头文件或调用哪些API , 就可以在第一天开始使用 ML,而无需学习API定义 。
9.4.3.3 How to use TVM with the
ML与TVM的集成已经开源并上游 。这种集成使开发人员能够轻松导入来自TVM支持的框架(如、、Keras、、MXnet和ONNX)的深度学习模型 。它尽可能地利用了TVM的图级优化和ML库内核 。对于扩展不支持的任何内核或操作符,BYOC提供了一个回退选项,可以使用TVM支持的任何后端 。
请查看带有 ML SDK的TVM存储库和位于高通开发者网络的博客:“ 使用TVM和 GPU上的ML API加速您的机器学习网络” 以获取更多详细信息 。
9.4.4 Otherfor ML 9.4.4.1ofdata
(brainpoint)浮点格式使用16位来表示32位浮点数的近似动态范围,通过保留八个指数位 。然而,它仅支持8位精度,而不是24位的FP32格式 。可用于减少数据存储需求 , 同时加速一些机器学习算法 。有关更多信息,请参考SDK 。
9.5 Other9.5.1 8-bit 操作
扩展引入了一组新的内建函数,用于计算具有一对四个8位分量的点积 , 然后将点积结果与32位累加器饱和相加 。对于此功能,必须启用以下编译器 #:
#pragma OPNCL EXTENSION cl_qcom_dot_product8 :
定义了两个函数,一个用于无符号8位整数,另一个用于有符号整数 。
描述例子
int (uint p0, uint p1,int acc);
假设p0和p1分别可以解释为四个无符号8位分量 , 而acc被解释为有符号32位累加器 。对这些分量的乘积求和,并将累加器加到结果中,得到一个带有有符号饱和的32位结果 。
计算向量 (11, 22, 33, 44) 和 (55, 66, 77, 88) 的无符号点积 , 并使用累加器为 9,示例1
int (uint p0, uint p1, int acc);
假设 p0 和 p1 分别可以解释为四个有符号8位分量和四个无符号8位分量,并且 acc 被解释为有符号32位累加器 。对这些分量的乘积求和,并将累加器加到结果中,得到一个带有有符号饱和的32位结果 。
计算向量 f(-11, 22, -33, 44) 和(55, 66, 77, 88) 的无符号点积,并使用累加器为 9,示例2
示例 1
uchar p0a = 11; uchar p0b = 22; uchar p0c = 33; uchar p0d = 44; uchar p1a = 55; uchar p1b = 66; uchar p1c = 77; uchar p1d = 88; uint p0 = (p0a << 24) | (p0b << 16) | (p0c << 8) | p0d; uint p1 = (p1a << 24) | (p1b << 16) | (p1c << 8) | p1d; int acc = 9; int result = qcom_udot8_acc(p0, p1, acc);
示例 2
uchar p0a = -11; uchar p0b = 22;uchar p0c = -33; uchar p0d = 44; uchar p1a = 55; uchar p1b = 66; uchar p1c = 77; uchar p1d = 88; uint p0 = (p0a << 24) | (p0b << 16) | (p0c << 8) | p0d; uint p1 = (p1a << 24) | (p1b << 16) | (p1c << 8) | p1d; int acc = 9; int result = qcom_dot8_acc(p0, p1, acc);
扩展也提供了类似的功能 。
9.5.2
该扩展引入了一种加速无符号整数位反转的新的内建函数 。使用此内建函数的应用程序相对于使用其他方法反转位的应用程序可能会获得性能优势 。对于此功能 , 必须启用 #。
#pragma OPNCL EXTENSION cl_qcom_bitreverse : enable //disable
一旦启用,函数就可以用于颠倒位的顺序 。以下是一个示例:
uint input = 0x1248edbf;uint output = qcom_bitreverse (input); //output = 0xfdb71248
更多操作请阅读SDK 开发文档关于的描述
- 玩ig是啥 igpu玩游戏需要打开吗
- 手机gpu屏幕合成是什么意思 手机gpu屏幕合成是什么意思呀
- ECharts数据可视化---你也可以如此炫酷
- 第一次作教学视频有感
- Echarts3之全国地图和省市地图二合一整合
- 新版pyecharts------3D地图结合热力图的一次探索
- 解决vue中echarts页面进入缩成一团的问题
- 基于Echarts的炫酷图表
- 手把手教 Vue3.2+Vite+Echarts 5 绘制3D线条效果中国地图
- 手动方法 将GPUImage库加入到本地项目中