高通OpenCL ML扩展之可记录队列
发表于 2022-09-23 12:27:15

高通的OpenCL驱动程序支持cl_qcom_recordable_queues扩展。这个扩展引入了一组新的处理流程来记录入队的内核序列,这样序列只需要生成一次,但可以多次分发调度。记录的序列称为recording,后面只需修改recording中任何内核的任何参数,而无需重新记录整个命令序列。对于重复入队固定序列的应用程序,现在只需对参数进行少量更改,就可以进行内核分发,这样节省了CPU并改善调度延迟。QCOM OpenCL SDK提供了示例,展示了应用程序如何使用可记录队列。

高通的OpenCL驱动程序还支持用于加速机器学习操作的cl_qcom_ml_ops扩展(CLML)。cl_qcom_ml_ops扩展可与cl_qcom_recordable_queues扩展一起用于记录ml ops。示例程序-clml_mobilenet_recordables已包含在OpenCL ML SDK中。此示例演示如何使用CLML和可记录队列来构建和运行mobilenet图像分类网络。

在clml_mobilenet_recordable示例中,cl_qcom_recordable_queues扩展允许更新ML Ops tensor数据,节省了重新创建op的开销。它演示了如何记录mobilenet模型,然后使用可记录队列API函数更新模型的输入tensor。

具体来说,我们将5个独立的内存区域依次配置到已记录的模型第一层输入tensor中,这样在不同的输入图像数据上连续运行模型5次。为了实现这一点,我们构造了一个cl_ml_tensor_memory_desc_qcom数组,该数组包含5个独立的cl_mem与单输入tensor的配对,即[{input_tensor, backing_memory_1}, {input_tensor, backing_memory_2}, ... ]。然后,我们用随机数据填充每个cl_mem,得到5组独立的输入数据,以便更新到模型的记录中。

现在,让我们看看具体实现:

1. 由于记录功能是由OpenCL可记录队列扩展提供的,因此我们需要加载/设置它。第一步是查询CL_DEVICE_EXTENSIONS,确认设备是否支持CL_qcom_recordable_queues功能

clGetDeviceInfo(device_id, CL_DEVICE_EXTENSIONS, extensions_size, buf.data(), NULL);

2. 创建两个命令队列,普通队列用于向gpu提交cmd,可记录队列用于cmd记录

queue = clCreateCommandQueue(context, device_id, queue_props, &result);
recordable_queue = clCreateCommandQueue(context, device_id, CL_QUEUE_RECORDABLE_QCOM, &result);

3. 然后我们开始记录。此记录有效期间(从现在起直到调用clEndRecordingQCOM)入队的任何操作都将添加到记录中

recording = clNewRecordingQCOM(recordable_queue, &result);

由于记录处于活动状态,因此对clEnqueueMLOpQCOM的入队cmd不执行,而是将其注册到记录队列中

for (size_t i = 0; i < operations.size(); ++i){
     result = h_ClmlIntf->clEnqueueMLOpQCOM(recordable_queue, operations[i], descriptorSet, 0, NULL, NULL);
}

clEndRecordingQCOM结束记录。在先前调用clNewRecordingQCOM和本次调用clEndRecordingQCOM之间排队的所有操作及其相应tensor都已添加到recording中

result = clEndRecordingQCOM(recording);

4. 我们为5个输入图像(由来自用户的两个连续图像组成)分配5个cl 内存对象。modelInputDescs数组充当模型输入tensor的“指针”,我们使用它来查询tensor的大小和分配内存。

for (int i = 0; i < 5; ++i){
   result = allocateTensorMemory(h_ClmlIntf, context, &(modelInputDescs[i]));
}
tensorMemDescs.push_back(modelInputDescs[0]);

5. 现在使用记录队列运行模型5次。

在第一次运行时,我们使用原始记录队列的输入,不更新任何记录的tensor

 result = h_ClmlIntf->clEnqueueRecordingMLOpQCOM(queue, recording, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL);

对于后面4次运行中的每一次,我们将使用其它图像内存更新输入tensor。modelInputDescs数组中的第一个值是我们原始记录的输入tensor,因此我们将把它支持得mem对象替换为具有不同输入数据的mem对象:

  // Now we run the model 5 times using our recording.
        // On the first run, we use the original recorded input and don't update any of the recording's tensors.
        // But on each of the 4 following runs, we update the input tensor with the other input memory allocations.
 for (int j = 0; j < 5; j++) {
cl_uint dispatch_index = 0;
cl_ml_tensor_memory_desc_qcom replacementDesc[] = {{modelInputDescs[0].tensor, modelInputDescs[j].memory}};
const cl_ml_op_array_arg_qcom replace_args[] = {{dispatch_index, &replacementDesc[0], 1}};
result = h_ClmlIntf->clEnqueueRecordingMLOpQCOM(queue, recording, 0, NULL, 1, replace_args, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, NULL);

现在我们已经介绍了CLML可记录队列,有关详细信息,请下载CLML sdk Qualcomm®Adreno™ OpenCL ML SDK,此功能通过较少的SetKernelArg/Enqueue操作来提高应用程序性能,从而在输入更改较少的情况下,让重复运行的ML模型获得更好的性能。

其他相关内容:

边缘机器学习训练:移动设备端训练

利用高通openCL ML SDK加速机器学习模型

作者:Ya Kong

CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
微博关注
【免责声明:CSDN本栏目发布信息,目的在于传播更多信息,丰富网络文化,稿件仅代表作者个人观点,与CSDN无关。其原创性以及文中陈述文字和文字内容未经本网证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本网不做任何保证或者承诺,请读者仅作参考,并请自行核实相关内容。您若对该稿件有任何怀疑或质疑,请立即与CSDN联系,我们将迅速给您回应并做处理。】