SlideShare a Scribd company logo
1 of 70
Download to read offline
Halideによる画像処理プログラミング入門
Fixstars Corp.
丸岡 晃
近村 啓史
0
DeepLearningの台頭
28.2
25.8
16.4
11.7
6.7
3.57
0
5
10
15
20
25
30
2010
NEC America
2011
Xerox
2012
AlexNet
2013
Clarifai
2014
GoogLeNet
2015
ResNet
Top-5Error[%]
ILSVRC ImageNet Classification
1
Deep Neural Networkによる
劇的な精度向上
http://image-net.org/challenges/talks/ilsvrc2015_deep_residual_learning_kaiminghe.pdf
DeepLearningを使った画像認識
 運転支援・自動運転
 工場での不良品検査
2
http://www.gapsis.jp/2015/01/nvidia-drive.html
http://www.itmedia.co.jp/enterprise/articles/1706/20/news049.html
https://gigazine.net/news/20160105-nvidia-drive-px2-demo/
本日の内容
 画像認識の高速化・低消費電力化の需要
 ムーアの法則の終焉
– ハードウェアが勝手に速くなる時代は終わった
– ハードウェアを効率良く使えるソフトウェア開発が必要
 画像処理プログラミング言語『Halide』の紹介
– 速く処理出来て
– 様々なハードウェアで動かせるプログラムが
– 短期間で簡単に開発出来る!
3
アジェンダ
Halide概要
アルゴリズム記述
スケジューリング記述
Halideの活用事例の紹介
フィックスターズにおける取り組みの紹介
4
Halide概要
5
Halideとは
画像処理の高性能計算に特化したDSL
(DSL: Domain Specific Language)
– http://halide-lang.org/
– C++の内部DSLとして提供
特徴
– アルゴリズムとスケジューリングの分離
– マルチプラットフォーム対応
• x86, ARM, PowerPC, NVIDIA GPGPUなど
に対するコード生成が可能
6
アルゴリズムとスケジューリングの分離
 アルゴリズム
– 計算部の本質的な処理のみを記述
– ハードウェアによらず単一の記述でよい
 スケジュール
– 計算順序やデータの保持の仕方を記述
– 並列化やループ変形などの最適化もここで記述
– ハードウェアごとに異なるスケジュールを指定可能
7
アルゴリズムとスケジュールの分離が可能
C++でのナイーブな実装コード
3x3Blurフィルターの実装例
8
void box_filter_3x3(const Image in, Image &blury) {
Image blurx(in.width(), in.height());
for (int y = 0; y < in.height(); y++)
for (int x = 0; x < in.width(); x++)
blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3;
for (int y = 0; y < in.height(); y++)
for (int x = 0; x < in.width(); x++)
blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3;
}
C++でのIntel向け手動最適化コード
9
void box_filter_3x3(const Image &in, Image &blury) {
__m128i one_third = _mm_set1_epi16(21846);
#pragma omp parallel for
for (int yTile = 0; yTile < in.height(); yTile += 32) {
__m128i a, b, c, sum, avg;
__m128i blurx[(256/8)*(32+2)]; // allocate tile blurx array
for (int xTile = 0; xTile < in.width(); xTile += 256) {
__m128i *blurxPtr = blurx;
for (int y = -1; y < 32+1; y++) {
const uint16_t *inPtr = &(in[yTile+y][xTile]);
for (int x = 0; x < 256; x += 8) {
a = _mm_loadu_si128((__m128i*)(inPtr-1));
b = _mm_loadu_si128((__m128i*)(inPtr+1));
c = _mm_load_si128((__m128i*)(inPtr));
sum = _mm_add_epi16(_mm_add_epi16(a, b), c);
avg = _mm_mulhi_epi16(sum, one_third);
_mm_store_si128(blurxPtr++, avg);
inPtr += 8;
}
}
blurxPtr = blurx;
for (int y = 0; y < 32; y++) {
__m128i *outPtr = (__m128i *)(&(blury[yTile+y][xTile]));
for (int x = 0; x < 256; x += 8) {
a = _mm_load_si128(blurxPtr+(2*256)/8);
b = _mm_load_si128(blurxPtr+256/8);
c = _mm_load_si128(blurxPtr++);
sum = _mm_add_epi16(_mm_add_epi16(a, b), c);
avg = _mm_mulhi_epi16(sum, one_third);
_mm_store_si128(outPtr++, avg);
}
}
}
}
}
C++でのIntel向け手動最適化コード
10
void box_filter_3x3(const Image &in, Image &blury) {
__m128i one_third = _mm_set1_epi16(21846);
#pragma omp parallel for
for (int yTile = 0; yTile < in.height(); yTile += 32) {
__m128i a, b, c, sum, avg;
__m128i blurx[(256/8)*(32+2)]; // allocate tile blurx array
for (int xTile = 0; xTile < in.width(); xTile += 256) {
__m128i *blurxPtr = blurx;
for (int y = -1; y < 32+1; y++) {
const uint16_t *inPtr = &(in[yTile+y][xTile]);
for (int x = 0; x < 256; x += 8) {
a = _mm_loadu_si128((__m128i*)(inPtr-1));
b = _mm_loadu_si128((__m128i*)(inPtr+1));
c = _mm_load_si128((__m128i*)(inPtr));
sum = _mm_add_epi16(_mm_add_epi16(a, b), c);
avg = _mm_mulhi_epi16(sum, one_third);
_mm_store_si128(blurxPtr++, avg);
inPtr += 8;
}
}
blurxPtr = blurx;
for (int y = 0; y < 32; y++) {
__m128i *outPtr = (__m128i *)(&(blury[yTile+y][xTile]));
for (int x = 0; x < 256; x += 8) {
a = _mm_load_si128(blurxPtr+(2*256)/8);
b = _mm_load_si128(blurxPtr+256/8);
c = _mm_load_si128(blurxPtr++);
sum = _mm_add_epi16(_mm_add_epi16(a, b), c);
avg = _mm_mulhi_epi16(sum, one_third);
_mm_store_si128(outPtr++, avg);
}
}
}
}
}
Halideでのアルゴリズム実装
11
Func box_filter_3x3(Func in) {
Func blurx, blury;
Var x, y;
blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3;
blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3;
return blury;
}
Halideでのアルゴリズム実装
12
Func box_filter_3x3(Func in) {
Func blurx, blury;
Var x, y;
blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3;
blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3;
return blury;
}
アルゴリズム記述部
アルゴリズムは本質的な処理の内容だけを記述
HalideでのIntel向け最適化実装
13
Func box_filter_3x3(Func in) {
Func blurx, blury;
Var x, y;
blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3;
blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3;
blury.tile(x, y, xi, yi, 256, 32).vectorize(xi, 8).parallel(y);
blurx.compute_at(blury, x).store_at(blury, x).vectorize(x, 8);
return blury;
}
少ないコード量と期間で簡単に最適化が可能
スケジューリング記述部
アルゴリズムは変更なし
マルチプラットフォーム向けの最適化
14
Func box_filter_3x3(Func in) {
Func blurx, blury;
Var x, y;
blurx(x, y) = (in(x-1, y) + in(x, y) + in(x+1, y))/3;
blury(x, y) = (blurx(x, y-1) + blurx(x, y) + blurx(x, y+1))/3;
if (target.has_gpu_feature()) {
Var tx, ty;
blury.gpu_tile(x, y, tx, ty, 32, 8);
} else {
blury.tile(x, y, xi, yi, 256, 32).vectorize(xi, 8).parallel(y);
blurx.compute_at(blury, x).store_at(blury, x).vectorize(x, 8);
}
return blury;
}
複数のハードウェアに対しても簡単に最適化が可能
GPU用のスケジューリング記述
Halideのコンパイルフロー
15
Halide
Compiler
Halide Program
C++ Compiler
Binary
Exec
LLVM-IR
LLVM
C.h.a/.o
C/C++ Compiler
Host Program
BinaryExec(JIT)
C/C++ Compiler
Binary
Halideのコンパイルフロー
16
Halide
Compiler
Halide Program
C++ Compiler
Binary
Exec
LLVM-IR
LLVM
C.h.a/.o
C/C++ Compiler
Host Program
BinaryExec(JIT)
C/C++ Compiler
Binary
Halideで記述された
ソースコードをコンパイル
Halideのコンパイルフロー
17
Halide
Compiler
Halide Program
C++ Compiler
Binary
Exec
LLVM-IR
LLVM
C.h.a/.o
C/C++ Compiler
Host Program
BinaryExec(JIT)
C/C++ Compiler
Binary
Halideコンパイラによる
コンパイルを実行
Halideのコンパイルフロー
18
Halide
Compiler
Halide Program
C++ Compiler
Binary
Exec
LLVM-IR
LLVM
C.h.a/.o
C/C++ Compiler
Host Program
BinaryExec(JIT)
C/C++ Compiler
Binary
LLVMバックエンド
によるコード生成
コンパイル時実行可能
(JITコンパイル)
実行前にコンパイルも可能
(AOTコンパイル)
Halideのコンパイルフロー
19
Halide
Compiler
Halide Program
C++ Compiler
Binary
Exec
LLVM-IR
LLVM
C.h.a/.o
C/C++ Compiler
Host Program
BinaryExec(JIT)
C/C++ Compiler
Binary
Cバックエンドによる
コード生成も対応
アルゴリズム記述
20
関数の定義
アルゴリズムは純粋関数として定義される
– 関数: Halide::Func
– 次元変数: Halide::Var
21
Func f;
Var x, y;
f(x, y) = x + y;
意味: 関数f は定義域 x, yに対して x + y を値域に持つ
名前空間 Halide:: は以下省略
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
f[y][x] = x + y;
}
}
等価なC++ソースコードHalideで書かれたソースコード
関数の次元数
最大4次元までの関数を定義可能
22
Func f;
Var c, x, y;
f(c, x, y) = c + x + y;
fは3次元の関数
(e.g. 3D空間, カラー画像)
関数の次元数
最大4次元までの関数を定義可能
23
Func f;
Var c, x, y;
f(c, x, y) = c + x + y;
Func f;
Var c, x, y, z;
f(c, x, y, z) = c + x + y + z;
fは3次元の関数
(e.g. 3D空間, カラー画像)
fは4次元の関数
関数の参照
関数の右辺に定義された関数を記述
右図の定義と同じ意味(合成関数)
24
Func f1, f2;
Var x, y;
f1(x, y) = x + y;
f2(x, y) = f1(x, y);
Func f2;
Var x, y;
f2(x, y) = x + y;
意味: 関数 f2 は定義域 x, yに対して f1(x, y) を値域に持つ
等価
式
式はExprクラスの変数として表される
– 関数: Func
– 次元変数: Var
– 式: Expr
25
組み立てた計算式を、式として取っておく事ができる
Func f;
Var x, y;
Expr e = x + y;
f(x, y) = e;
Func f;
Var x, y;
f(x, y) = x + y;
等価
即値
C++の数値リテラルは式の定義に使用可
– 暗黙的型変換によりExpr型にキャストされる
26
意味: 関数 f はどのような定義域に対しても値域 1 を持つ
Func f;
Var x, y;
f(x, y) = 1;
RDomと畳み込み関数
 リダクションドメイン: Rdom
– RDom(min, extent)
– 指定された次元で[min, min+extent-1]の領域を動く
ループ変数
27
rx は[-1, 1] を動くループ変数
Func f, g;
Var x;
RDom rx(-1, 3)
f(x) = x;
g(x) = sum(f(x + rx));
for (int x=0; x<width; x++) {
T sum = 0;
for (int rx=-1; rx<2; rx++) {
sum += x + rx;
}
g[x] = sum;
}
等価なC++ソースコード
RDomと畳み込み関数
 畳み込み関数:
– RDomで指定した領域を畳み込んで演算を行う関数
• 例: sum/product/maximum/minimum/argmin/argmax
28
Func f, g;
Var x;
RDom rx(-1, 3)
f(x) = x;
g(x) = sum(f(x + rx));
関数 g は各xにおいて、x-1, x+0, x+1の総和を値域に持つ
for (int x=0; x<width; x++) {
T sum = 0;
for (int rx=-1; rx<2; rx++) {
sum += x + rx;
}
g[x] = sum;
}
等価なC++ソースコード
領域外アクセス時の参照値設定
 BoundaryConditions
– constant_exterior: 指定した定数値を参照
– repeat_edge: 袖領域を拡張して参照
– mirror_image: 画像を反転して複製するように参照
– etc…
29
Func f, f_, g;
Var x;
RDom rx(-1, 3)
f(x) = x;
f_ = BoundaryConditions::constant_exterior(f, 0)
g(x) = sum(f_(x + rx));
関数 f は定義域 x<0 または x>=width のとき、値 0 を返す
アルゴリズムの記述例
2次元Convolutionを実装してみよう
30
2次元Convolution
31
𝐷𝑠𝑡 𝑥, 𝑦 =
𝑘𝑦=0
𝑘ℎ
𝑘𝑥=0
𝑘𝑤
𝑆𝑟𝑐 𝑥 + 𝑘𝑥 −
𝑘𝑤
2
, 𝑦 + 𝑘𝑦 −
𝑘ℎ
2
× 𝐾𝑒𝑟𝑛𝑒𝑙(𝑘𝑥, 𝑘𝑦)
 2次元画像の畳み込み処理
– 画像処理において頻繁に用いられる処理
= ∗
2次元Convolution
32
 例: 画像処理フィルタ
– ぼかしやエッジ検出、ノイズ除去などの様々な
画像処理に使用されている
1
16
1
8
1
16
1
8
1
4
1
8
1
16
1
8
1
16
−1 −1 −1
−1 8 −1
−1 −1 −1
=
∗
=
Gaussian Kernel
Laplacian Kernel
ぼかし処理
エッジ検出
DeepLearningにおけるConvolution
 Convolutional Neural Network
– 画像認識に使用されるニューラルネットワーク
– 推論時はConvolution層が全体の処理時間の50%以上を占める
• 最近のネットワークではConvolution層の多段化により
さらに処理時間が増加
 Convolution層の高速化はとても重要!
33
Convolution層
LeNetのネットワーク図
Y. LeCun, L. Bottou, Y. Bengio, and P. Haffner. Gradient-based learning
applied to document recognition. Proceedings of the IEEE, november 1998.
2次元Convolutionのアルゴリズム記述
 C++での実装例
34
void conv3x3(const uint8_t* src, const float* kernel, uint8_t* dst,
int height, int width) {
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
float tmp = .0f;
for (int ky=0; ky<kh; ky++) {
for (int kx=0; kx<kw; kx++) {
tmp += src[y+ky-kh/2][x+kx-kw/2] * kernel[ky][kx];
}
}
dst[y][x] = tmp;
}
}
}
2次元Convolutionのアルゴリズム記述
 Generator インタフェースに従った記述例
– ターゲットや出力形式、コンパイル時パラメータを
コンパイル時に指定可能
35
class conv3x3 : public Generator<conv3x3>{
Var x{"x"}, y{"y"};
public:
Input<Buffer<uint8_t>> src{“src", 2};
Input<Buffer<float>> kernel{"kernel", 2};
Output<Buffer<uint8_t>> dst{“dst", 2};
void generate() {
RDom r(-1, 3, -1, 3, "r");
Func src_ = BoundaryConditions::repeat_edge(in);
dst(x, y) = cast<uint8_t>(sum(cast<float>(src_(x+r.x, y+r.y)) * kernel(r.x+1, r.y+1)));
}
};
HALIDE_REGISTER_GENERATOR(conv3x3, conv3x3)
2次元Convolutionのアルゴリズム記述
 Generator インタフェースに従った記述例
– ターゲットや出力形式、コンパイル時パラメータを
コンパイル時に指定可能
36
class conv3x3 : public Generator<conv3x3>{
Var x{"x"}, y{"y"};
public:
Input<Buffer<uint8_t>> src{“src", 2};
Input<Buffer<float>> kernel{"kernel", 2};
Output<Buffer<uint8_t>> dst{“dst", 2};
void generate() {
RDom r(-1, 3, -1, 3, "r");
Func src_ = BoundaryConditions::repeat_edge(in);
dst(x, y) = cast<uint8_t>(sum(cast<float>(src_(x+r.x, y+r.y)) * kernel(r.x+1, r.y+1)));
}
};
HALIDE_REGISTER_GENERATOR(conv3x3, conv3x3)
入出力パラメータ
アルゴリズムの記述部
Generatorを登録
スケジューリング記述
37
スケジューリングとは
ハードウェアの特性に応じて、
性能を向上させるための様々な指定
– 計算タイミングの指定
– スレッド並列化
– ベクトル化
– ループ変形
– etc…
スケジューリングはターゲットハードウェア
によって達成される効果が異なります
– 今回はCPUの場合について紹介します
38
計算タイミングの指定
 Func::compute_inline (デフォルト)
– 出力のFunc以外はインライン展開される
• 〇必要メモリ量は少なくなる
• ×計算量が増える可能性あり
39
等価
Func blur_x, blur_y;
Var x, y;
blur_x(x, y) =
in(x, y) + in(x+1, y);
blur_y(x, y) =
(blur_x(x, y) + blur_x(x, y+1)) / 4;
Func blur_y;
Var x, y;
blur_y(x, y) =
(in(x, y) + in(x+1, y) +
in(x, y+1) + in(x+1, y+1)) / 4;
計算タイミングの指定
 Func::compute_root
– 関数の全領域の計算結果がメモリに保持される
• 〇計算量が削減できる可能性あり
• ×必要メモリ量は多くなる
40
Func blur_x, blur_y;
Var x, y;
blur_x(x, y) =
in(x, y) + in(x+1, y);
blur_y(x, y) =
(blur_x(x, y) + blur_x(x, y+1)) / 4;
blur_x.compute_root();
blur_xはblur_yを評価する前に全領域が計算される
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
blur_x[y][x] = in[y][x] + in[y][x+1];
}
}
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
blur_y[y][x] =
(blur_x[y][x] + blur_x[y+1][x]) / 4;
}
}
計算タイミングの指定
 Func::compute_at
– 指定した関数の次元のループ内で必要な領域のみの
計算結果がメモリに保持される
• 計算量・メモリ使用量共に
compute_inlineとcompute_rootの中間となる
41
blur_xはblur_yのyループ内で必要な領域が計算される
for (int y=0; y<height; y++) {
for (int x=0; x<width; x++) {
blur_x[0][x] = in[y][x] + in[y][x+1];
blur_x[1][x] =
in[y+1][x] + in[y+1][x+1];
}
for (int x=0; x<width; x++) {
blur_y[y][x] =
(blur_x[0][x] + blur_x[1][x]) / 4;
}
}
Func blur_x, blur_y;
Var x, y;
blur_x(x, y) =
in(x, y) + in(x+1, y);
blur_y(x, y) =
(blur_x(x, y) + blur_x(x, y+1)) / 4;
blur_x.compute_at(blue_y, y);
スレッド並列化
 Func::parallel
– 指定した次元でループをスレッド並列化
– 各スレッドを異なるコアで実行することで高速化
42
Func f;
Var x, y;
f(x, y) = x + y;
f.parallel(y);
Thread 0
Thread 1
x
y
f
Parallelize
fの計算が2スレッドで並列に処理される
ベクトル化
 Func::vectorize
– 指定した次元とベクトル幅でループをベクトル化
 ベクトル化
– SIMD命令を使用するように最適化すること
• 1命令で複数のデータを同時に演算可能
• 例: Intel SSE/AVX, ARM NEON, Power AltiVec など
43
Func f, g, h;
Var x;
f(x) = g(x) + h(x);
+
g
h
f
1命令あたり1要素ずつ演算される
ベクトル化
 Func::vectorize
– 指定した次元とベクトル幅でループをベクトル化
 ベクトル化
– SIMD命令を使用するように最適化すること
• 1命令で複数のデータを同時に演算可能
• 例: Intel SSE/AVX, ARM NEON, Power AltiVec など
44
Func f, g, h;
Var x;
f(x) = g(x) + h(x);
f.vectorize(x, 4);
+
g
h
f
1命令で4要素が同時に演算される
Vectorize
ループアンロール
 Func::unroll
– 指定した次元に対してループ展開を行う
• 分岐命令の削減
• ソフトウェアパイプライニング
• レジスタの再利用(レジスタブロッキング)
45
for (int y=0; y<height; y++)
for (int x=0; x<width; x++)
f[y][x] = x + y;
unroll前の等価なC++ソースコード
Func f;
Var x, y;
f(x, y) = x + y;
ループアンロール
 Func::unroll
– 指定した次元に対してループ展開を行う
• 分岐命令の削減
• ソフトウェアパイプライニング
• レジスタの再利用(レジスタブロッキング)
46
Func f;
Var x, y;
f(x, y) = x + y;
f.unroll(x, 2);
for (int y=0; y<height; y++)
for (int x=0; x<width; x+=2) {
f[y][x] = x + y;
f[x+1][y] = x+1 + y;
}
for (int y=0; y<height; y++)
for (int x=0; x<width; x++)
f[y][x] = x + y;
unroll前の等価なC++ソースコード
Unroll後の等価なC++ソースコード
Unroll
タイリング
 Func::tile
– 指定した次元とタイルサイズでループをタイル化する
• データの再利用性を高める
⇒キャッシュやローカルメモリなどを有効活用できる
47
Func f;
Var x, y;
f(x, y) = in(y, x);
f.tile(x, y, xi, yi, 16, 16);
for (int y=0; y<height; y+=16) {
for (int x=0; x<width; x+=16) {
for(int yi = 0; yi < 16; yi++) {
for(int xi = 0; xi < 16; xi++) {
f[y+yi][x+xi] = in[x+xi][y+yi];
}
}
}
}
Tile後の等価なC++ソースコード
スケジューリングの適用例
2次元Convolutionを最適化してみよう
48
2次元Convolutionのスケジュール記述
 Generator インタフェースに従った記述例
– schedule関数内にスケジューリングを記述
49
class conv3x3 : public Generator<conv3x3>{
Var x{"x"}, y{"y"};
public:
Input<Buffer<uint8_t>> src{“src", 2};
Input<Buffer<float>> kernel{"kernel", 2};
Output<Buffer<uint8_t>> dst{"dst", 2};
void generate() {
RDom r(-1, 3, -1, 3, "r");
Func src_ = BoundaryConditions::repeat_edge(src);
dst(x, y) = cast<uint8_t>(sum(cast<float>(src_(x+r.x, y+r.y)) * kernel(r.x+1, r.y+1)));
}
void schedule() {
}
};
スケジューリングを記述
性能評価環境
 評価環境
– CPU: Intel Core i7-5930K
• 周波数: 3.5GHz
• 6コア12スレッド
• AVX2/FMA3搭載(1命令で256-bit幅の積和演算が可能)
– コンパイラ
• GCC-6.3.0 (C++実装用のコンパイラとして使用)
• Halide: Release-2017_10_31 & LLVM-5.0.0
• コンパイルオプション: -O3 –march=native
 2次元Convolution
– 入出力: 2048x2048 8-bitグレースケール画像
– カーネルサイズ: 3x3
– カーネル: Gaussianカーネル
50
アルゴリズム実装のみの性能
66.4
3.61
0
10
20
30
40
50
60
70
①: C++ ②: Halide
ExecutionTime[ms]
51
 Halideで実装するだけで18.4倍の速度向上
– Halide版はLLVMで自動ベクトル化されているのを確認
18.4倍
ループ展開によるレジスタブロッキング
52
 通常のConvolution演算
– 出力1画素の計算当たり
入力9画素のロードが必要
dst src
unroll前の参照範囲
ループ展開によるレジスタブロッキング
53
 通常のConvolution演算
– 出力1画素の計算当たり
入力9画素のロードが必要
 Yの次元でループを展開してみると…?
– 出力2画素の計算当たり
入力12画素のロードで済む
⇒ロード命令の削減が可能!
dst src
dst src
unroll前の参照範囲
unroll後の参照範囲
ループ展開によるレジスタブロッキング
54
スケジューリングの記述
void generate() {
RDom r(-1, 3, -1, 3, "r");
Func src_ = BoundaryConditions::repeat_edge(src);
dst(x, y) =
cast<uint8_t>(sum(cast<float>(src_(x+r.x, y+r.y)) * kernel(r.x+1, r.y+1)));
}
void schedule() {
out.split(y, yo, yi, 4);
out.reorder(yi, x, yo);
out.unroll(yi);
}
Y次元で4展開分のループアンロール
ループアンロール適用後の性能
66.4
3.61 3.17
0
10
20
30
40
50
60
70
①: C++ ②: Halide ③: ②+unroll
ExecutionTime[ms]
55
20.9倍
 ロード命令の削減により1.14倍の速度向上
スレッド並列化
 Yの次元でスレッド並列化を適用
56
void generate() {
RDom r(-1, 3, -1, 3, "r");
Func src_ = BoundaryConditions::repeat_edge(src);
dst(x, y) =
cast<uint8_t>(sum(cast<float>(src_(x+r.x, y+r.y)) * kernel(r.x+1, r.y+1)));
}
void schedule() {
out.split(y, yo, yi, 4);
out.reorder(yi, x, yo);
out.unroll(yi);
out.parallel(yo);
}
Yの次元でスレッド並列化
スレッド並列化適用後の性能
66.4
3.61 3.17 0.52
0
10
20
30
40
50
60
70
①: C++ ②: Halide ③: ②+unroll ④: ③+parallel
ExecutionTime[ms]
57
127.7倍
 スレッド並列化により6.10倍の速度向上
– スケジューリングを4行追加するだけで127.7倍の速度向上
参考情報
公式ページ
– http://halide-lang.org/
リファレンス
– http://halide-lang.org/docs/index.html
チュートリアル
– http://halide-
lang.org/tutorials/tutorial_introduction.html
58
Halideの活用事例の紹介
59
OpenCVのDNNモジュール
60
 DNNモジュールに
Halide実装が追加
– ネットワークごとに各層の
スケジューリングを定義可能
– IntelCPU上でMKLを使用した
場合と同等程度の性能
https://docs.opencv.org/3.3.0/de/d37/tutorial_dnn_halide.html
https://www.slideshare.net/embeddedvision/making-opencv-
code-run-fast-a-presentation-from-intel
NNVM/TVM
61
 NNVM
– 各種DeepLearningフレームワークで記述されたコードを様々な
ターゲットハードウェア向けに最適化・コード生成を行うコンパイラ
 TVM
– テンソル演算用の中間表現スタック
– 中間表現としてHalideのIRを拡張し採用
http://www.tvmlang.org/2017/10/06/nnvm-compiler-announcement.html
http://tvmlang.org
Google Pixel2
62
 Googleが発表したスマートフォン
 画像処理・機械学習用のカスタムSoC
「Pixel Visual Core」を搭載
– 8個のIPU(Image Processing Unit)を搭載
– IPUはTensorFlowとHalideによる開発をサポート
https://techcrunch.com/2017/10/17/googles-first-custom-consumer-chip-is-the-secret-behind-the-pixel-2s-camera-performance
フィックスターズにおける
Halideへの取り組み
© 2017 Fixstars Corp. CONFIDENTIAL
63
Fixstars Solutions, Inc.(米国カリフォルニア州、100%子会社)
株式会社アイ・イー・テック(株式会社SHIFTとの合弁会社、当社出資比率:66%)
Who am I?
© 2017 Fixstars Corp. CONFIDENTIAL
64
フィックスターズとは?
マルチコアプロセッサ/フラッシュメモリを駆使して
大量計算や大量データI/Oの高速処理を実現するソフトウェア・パートナーです
事業内容 マルチコアプロセッサ関連事業
設立 2002年8月
資本金 5億4,996万円 (2016年12月末 現在)
社員数 150名(2017年9月末 現在)
所在地 大崎(本社)、横浜
代表取締役社長 三木 聡
主な取引先 東芝、キヤノン、デンソー、日立製作所、日立ハイテクノロジーズ、オリンパス、みず
ほ証券、 宇宙航空研究開発機構など
連結子会社
本社:品川区大崎
Halide to FPGA(Beta)のサイトオープン
© 2017 Fixstars Corp. CONFIDENTIAL
65
10月18日にサイトをオープンしています
Halide to FPGA 概要
GPUCPU FPGA
GenesisコンパイラがHalide ベースのプログラムコードを
FPGA向けのコードへと変換します
Halideアプリケーション
プログラム
Genesis コンパイラ
© 2017 Fixstars Corp. CONFIDENTIAL
66
FPGA?
67
FPGA:Field Programmable Gate Array
製造後に購入者や設計者が構成を設定できる
集積回路
従来ASICと比較して低速でエネルギー効率が
悪いというデメリットがあったが、製造ルー
ル微細化の最先端を走り、ギャップは縮まり
つつある
高い並列性のあるアルゴリズムの
実装に適している
コンパイルフロー
68
Bitstream
Netlist
RTL
Vivado HLS C/C++
Halide
高位合成ツール
Genesisコンパイラ
論理合成/配置配線/
タイミング検証ツール
© 2017 Fixstars Corp. CONFIDENTIAL
ターゲットハードウェアで
一般的なEDAツールを
使用する
従来は手動で行っていた
アルゴリズムから
量産用実装への変換を
Genesisコンパイラで置き換える
RTL生成部は
高位合成ツールに任せる
ありがとうございました
69

More Related Content

What's hot

組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
Norishige Fukushima
 

What's hot (20)

組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
マルチコアを用いた画像処理
マルチコアを用いた画像処理マルチコアを用いた画像処理
マルチコアを用いた画像処理
 
近年のHierarchical Vision Transformer
近年のHierarchical Vision Transformer近年のHierarchical Vision Transformer
近年のHierarchical Vision Transformer
 
いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例いまさら聞けないarmを使ったNEONの基礎と活用事例
いまさら聞けないarmを使ったNEONの基礎と活用事例
 
プログラムを高速化する話Ⅱ 〜GPGPU編〜
プログラムを高速化する話Ⅱ 〜GPGPU編〜プログラムを高速化する話Ⅱ 〜GPGPU編〜
プログラムを高速化する話Ⅱ 〜GPGPU編〜
 
第 1 回 Jetson ユーザー勉強会
第 1 回 Jetson ユーザー勉強会第 1 回 Jetson ユーザー勉強会
第 1 回 Jetson ユーザー勉強会
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
 
画像処理ライブラリ OpenCV で 出来ること・出来ないこと
画像処理ライブラリ OpenCV で 出来ること・出来ないこと画像処理ライブラリ OpenCV で 出来ること・出来ないこと
画像処理ライブラリ OpenCV で 出来ること・出来ないこと
 
TensorRT Inference Serverではじめる、 高性能な推論サーバ構築
TensorRT Inference Serverではじめる、 高性能な推論サーバ構築TensorRT Inference Serverではじめる、 高性能な推論サーバ構築
TensorRT Inference Serverではじめる、 高性能な推論サーバ構築
 
グラフニューラルネットワーク入門
グラフニューラルネットワーク入門グラフニューラルネットワーク入門
グラフニューラルネットワーク入門
 
モデル高速化百選
モデル高速化百選モデル高速化百選
モデル高速化百選
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
 
Hopper アーキテクチャで、変わること、変わらないこと
Hopper アーキテクチャで、変わること、変わらないことHopper アーキテクチャで、変わること、変わらないこと
Hopper アーキテクチャで、変わること、変わらないこと
 
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
CPU / GPU高速化セミナー!性能モデルの理論と実践:理論編
 
Tensorflow Liteの量子化アーキテクチャ
Tensorflow Liteの量子化アーキテクチャTensorflow Liteの量子化アーキテクチャ
Tensorflow Liteの量子化アーキテクチャ
 
製造業向け量子コンピュータ時代のDXセミナー~ 最適化の中身を覗いてみよう~
製造業向け量子コンピュータ時代のDXセミナー~ 最適化の中身を覗いてみよう~製造業向け量子コンピュータ時代のDXセミナー~ 最適化の中身を覗いてみよう~
製造業向け量子コンピュータ時代のDXセミナー~ 最適化の中身を覗いてみよう~
 
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
3種類のTEE比較(Intel SGX, ARM TrustZone, RISC-V Keystone)
 
SAT/SMTソルバの仕組み
SAT/SMTソルバの仕組みSAT/SMTソルバの仕組み
SAT/SMTソルバの仕組み
 
CUDAプログラミング入門
CUDAプログラミング入門CUDAプログラミング入門
CUDAプログラミング入門
 

Similar to Halide による画像処理プログラミング入門

LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
Takeshi Yamamuro
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
Kiwamu Okabe
 
PF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsolaPF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsola
android sola
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml
ssuser3a4b8c
 

Similar to Halide による画像処理プログラミング入門 (20)

Slide
SlideSlide
Slide
 
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
GPUが100倍速いという神話をぶち殺せたらいいな ver.2013
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database AnalyticsPL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
PL/CUDA - Fusion of HPC Grade Power with In-Database Analytics
 
Python Data-Visualization Package Status
Python Data-Visualization Package StatusPython Data-Visualization Package Status
Python Data-Visualization Package Status
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
 
Prosym2012
Prosym2012Prosym2012
Prosym2012
 
20181212 - PGconf.ASIA - LT
20181212 - PGconf.ASIA - LT20181212 - PGconf.ASIA - LT
20181212 - PGconf.ASIA - LT
 
LLVM最適化のこつ
LLVM最適化のこつLLVM最適化のこつ
LLVM最適化のこつ
 
llvm入門
llvm入門llvm入門
llvm入門
 
Rを用いたGIS
Rを用いたGISRを用いたGIS
Rを用いたGIS
 
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望TPC-DSから学ぶPostgreSQLの弱点と今後の展望
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
 
PF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsolaPF部2011年12月勉強会.androidsola
PF部2011年12月勉強会.androidsola
 
フラグを愛でる
フラグを愛でるフラグを愛でる
フラグを愛でる
 
Fpga online seminar by fixstars (1st)
Fpga online seminar by fixstars (1st)Fpga online seminar by fixstars (1st)
Fpga online seminar by fixstars (1st)
 
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
 
C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml C base design methodology with s dx and xilinx ml
C base design methodology with s dx and xilinx ml
 
20200828_OSCKyoto_Online
20200828_OSCKyoto_Online20200828_OSCKyoto_Online
20200828_OSCKyoto_Online
 
コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道コンピューティングとJava~なにわTECH道
コンピューティングとJava~なにわTECH道
 
【関東GPGPU勉強会#4】GTX 1080でComputer Vision アルゴリズムを色々動かしてみる
【関東GPGPU勉強会#4】GTX 1080でComputer Visionアルゴリズムを色々動かしてみる【関東GPGPU勉強会#4】GTX 1080でComputer Visionアルゴリズムを色々動かしてみる
【関東GPGPU勉強会#4】GTX 1080でComputer Vision アルゴリズムを色々動かしてみる
 

More from Fixstars Corporation

More from Fixstars Corporation (20)

製造業向け量子コンピュータ時代のDXセミナー_生産計画最適化_20220323.pptx
製造業向け量子コンピュータ時代のDXセミナー_生産計画最適化_20220323.pptx製造業向け量子コンピュータ時代のDXセミナー_生産計画最適化_20220323.pptx
製造業向け量子コンピュータ時代のDXセミナー_生産計画最適化_20220323.pptx
 
CPU / GPU高速化セミナー!性能モデルの理論と実践:実践編
CPU / GPU高速化セミナー!性能モデルの理論と実践:実践編CPU / GPU高速化セミナー!性能モデルの理論と実践:実践編
CPU / GPU高速化セミナー!性能モデルの理論と実践:実践編
 
製造業向け量子コンピュータ時代のDXセミナー ~見える化、分析、予測、その先の最適化へ~
製造業向け量子コンピュータ時代のDXセミナー ~見える化、分析、予測、その先の最適化へ~製造業向け量子コンピュータ時代のDXセミナー ~見える化、分析、予測、その先の最適化へ~
製造業向け量子コンピュータ時代のDXセミナー ~見える化、分析、予測、その先の最適化へ~
 
株式会社フィックスターズの会社説明資料(抜粋)
株式会社フィックスターズの会社説明資料(抜粋)株式会社フィックスターズの会社説明資料(抜粋)
株式会社フィックスターズの会社説明資料(抜粋)
 
Jetson活用セミナー ROS2自律走行実現に向けて
Jetson活用セミナー ROS2自律走行実現に向けてJetson活用セミナー ROS2自律走行実現に向けて
Jetson活用セミナー ROS2自律走行実現に向けて
 
量子コンピュータ時代の製造業におけるDXセミナー~生産工程効率化に向けた新たなご提案~
量子コンピュータ時代の製造業におけるDXセミナー~生産工程効率化に向けた新たなご提案~量子コンピュータ時代の製造業におけるDXセミナー~生産工程効率化に向けた新たなご提案~
量子コンピュータ時代の製造業におけるDXセミナー~生産工程効率化に向けた新たなご提案~
 
金融業界向けセミナー 量子コンピュータ時代を見据えた組合せ最適化
金融業界向けセミナー 量子コンピュータ時代を見据えた組合せ最適化金融業界向けセミナー 量子コンピュータ時代を見据えた組合せ最適化
金融業界向けセミナー 量子コンピュータ時代を見据えた組合せ最適化
 
株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)
 
株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)
 
ソフト高速化の専門家が教える!AI・IoTエッジデバイスの選び方
ソフト高速化の専門家が教える!AI・IoTエッジデバイスの選び方ソフト高速化の専門家が教える!AI・IoTエッジデバイスの選び方
ソフト高速化の専門家が教える!AI・IoTエッジデバイスの選び方
 
AIチップ戦国時代における深層学習モデルの推論の最適化と実用的な運用を可能にするソフトウェア技術について
AIチップ戦国時代における深層学習モデルの推論の最適化と実用的な運用を可能にするソフトウェア技術についてAIチップ戦国時代における深層学習モデルの推論の最適化と実用的な運用を可能にするソフトウェア技術について
AIチップ戦国時代における深層学習モデルの推論の最適化と実用的な運用を可能にするソフトウェア技術について
 
株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)
 
第8回 社内プログラミングコンテスト 結果発表会
第8回社内プログラミングコンテスト 結果発表会第8回社内プログラミングコンテスト 結果発表会
第8回 社内プログラミングコンテスト 結果発表会
 
第8回 社内プログラミングコンテスト 第1位 taiyo
第8回社内プログラミングコンテスト 第1位 taiyo第8回社内プログラミングコンテスト 第1位 taiyo
第8回 社内プログラミングコンテスト 第1位 taiyo
 
第8回 社内プログラミングコンテスト 第2位 fy999
第8回社内プログラミングコンテスト 第2位 fy999第8回社内プログラミングコンテスト 第2位 fy999
第8回 社内プログラミングコンテスト 第2位 fy999
 
第8回 社内プログラミングコンテスト 第3位 logicmachine
第8回社内プログラミングコンテスト 第3位 logicmachine第8回社内プログラミングコンテスト 第3位 logicmachine
第8回 社内プログラミングコンテスト 第3位 logicmachine
 
株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)株式会社フィックスターズ 会社説明資料(抜粋)
株式会社フィックスターズ 会社説明資料(抜粋)
 
A challenge for thread parallelism on OpenFOAM
A challenge for thread parallelism on OpenFOAMA challenge for thread parallelism on OpenFOAM
A challenge for thread parallelism on OpenFOAM
 
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化についてマルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
マルチレイヤコンパイラ基盤による、エッジ向けディープラーニングの実装と最適化について
 
DIC-PCGソルバーのpimpleFoamに対する時間計測と高速化
DIC-PCGソルバーのpimpleFoamに対する時間計測と高速化DIC-PCGソルバーのpimpleFoamに対する時間計測と高速化
DIC-PCGソルバーのpimpleFoamに対する時間計測と高速化
 

Halide による画像処理プログラミング入門