このブログは、株式会社フィックスターズのエンジニアが、あらゆるテーマについて自由に書いているブログです。
最近のGPUは、動画エンコーダを実装しているものが多いです。
Intel社のGPUは、この動画エンコーダで使われる、ブロック単位での動き予測ハードウェアを、OpenCLから使うことができます。
公式の解説 : https://software.intel.com/en-us/articles/intro-to-motion-estimation-extension-for-opencl
公式のサンプル : https://software.intel.com/en-us/articles/video-motion-estimation-using-opencl
公式のサンプルに気付かないで作ってしまったサンプル : https://bitbucket.org/fixstars/blog/src/95aecef11221e15d291076f815e171a4c7671e35/me/?at=master
手順は以下のとおりです。
clGetExtensionFunctionAddressForPlatform で、 “clCreateAcceleratorINTEL” のポインタを取得します。これは、デバイスが “cl_intel_accelerator” 拡張を持っているときに有効です。
p_clCreateAccelrator = (clCreateAcceleratorINTEL_fn)
clGetExtensionFunctionAddressForPlatform(cl_plt(), "clCreateAcceleratorINTEL");
これを使って、cl_accelerator_intel を作ります。
me_block_typeでブロックサイズを決めます。me_search_path_type で探索範囲を決めます。subpixel_mode は hpel, qpel などが選べるようです。sad_adjust_mode はすいません、よくわかりませんでした。普通にSADの場合は上のようにすればよいと思います。
cl_motion_estimation_desc_intel me_desc = {0};
switch (blk_size) {
case 4:
me_desc.mb_block_type = CL_ME_MB_TYPE_4x4_INTEL;
break;
case 8:
me_desc.mb_block_type = CL_ME_MB_TYPE_8x8_INTEL;
break;
case 16:
me_desc.mb_block_type = CL_ME_MB_TYPE_16x16_INTEL;
break;
default:
printf("blk_size=%d is not supported\n", blk_size);
return -1;
}
switch (radius) {
case 2:
me_desc.search_path_type = CL_ME_SEARCH_PATH_RADIUS_2_2_INTEL;
break;
case 4:
me_desc.search_path_type = CL_ME_SEARCH_PATH_RADIUS_4_4_INTEL;
break;
case 16:
me_desc.search_path_type = CL_ME_SEARCH_PATH_RADIUS_16_12_INTEL;
break;
default:
printf("radius=%d is not supported\n", radius);
return -1;
}
me_desc.subpixel_mode = CL_ME_SUBPIXEL_MODE_INTEGER_INTEL;
me_desc.sad_adjust_mode = CL_ME_SAD_ADJUST_MODE_NONE_INTEL;
cl_int err;
accelerator = p_clCreateAccelrator(gpu_context(),
CL_ACCELERATOR_TYPE_MOTION_ESTIMATION_INTEL,
sizeof(me_desc),
&me_desc,
&err);
block_motion_estimate_intel カーネルを作ります。
cl.hpp を使っているのでわかりづらいですが、OpenCL 1.2には、こういう特殊なカーネルを作る場合のために、 clCreateProgramWithBuiltInKernels というのがあります。これを使っています。
cl::Program me_prog(gpu_context, gpu_devs, "block_motion_estimate_intel");
me_kernel = cl::Kernel(me_prog, "block_motion_estimate_intel");
カーネルに引数を設定します。block_motion_estimate_intelカーネルの引数は、
_kernel void
block_motion_estimate_intel
(
accelerator_intel_t accelerator,
__read_only image2d_t src_image,
__read_only image2d_t ref_image,
__global short2 * prediction_motion_vector_buffer,
__global short2 * motion_vector_buffer,
__global ushort * residuals
);
と、なっていてそれぞれ、
です。
時間を計測したところ、720p で 1.5~3.5[msec] 程度のようです。
簡単に書いた C++(OpenMPあり)だと、i7-4700MQ(2.4GHz 4core 8thread)で 65msecなので、それより20~40倍ぐらい速いですね。SADのBMはSIMDで速くなるのであまり良い比較ではないですが、さすがに20倍にはならないので、速いと言っていいと思います。
Atomのように小さいCPUだとより使うメリットは大きいですね、Atom Z3740 では 720p で、7[msec]程度で実行できるようです。
コンピュータビジョンセミナーvol.2 開催のお知らせ - ニュース一覧 - 株式会社フィックスターズ in Realizing Self-Driving Cars with General-Purpose Processors 日本語版
[…] バージョンアップに伴い、オンラインセミナーを開催します。 本セミナーでは、...
【Docker】NVIDIA SDK Managerでエラー無く環境構築する【Jetson】 | マサキノート in NVIDIA SDK Manager on Dockerで快適なJetsonライフ
[…] 参考:https://proc-cpuinfo.fixstars.com/2019/06/nvidia-sdk-manager-on-docker/ […]...
Windowsカーネルドライバを自作してWinDbgで解析してみる① - かえるのほんだな in Windowsデバイスドライバの基本動作を確認する (1)
[…] 参考:Windowsデバイスドライバの基本動作を確認する (1) - Fixstars Tech Blog /proc/cpuinfo ...
2021年版G検定チートシート | エビワークス in ニューラルネットの共通フォーマット対決! NNEF vs ONNX
[…] ONNX(オニキス):Open Neural Network Exchange formatフレームワーク間のモデル変換ツー...
YOSHIFUJI Naoki in CUDAデバイスメモリもスマートポインタで管理したい
ありがとうございます。別に型にこだわる必要がないので、ユニバーサル参照を受けるよ...