12. 12
Schedule : parallel
Fork/Joinの並列処理
? Taskを生成しQueueに入れる
? Worker-threadが実行
? 全taskの実行完了を待つ
f3
x
y
z
//デフォルト (シリアル実行)
//疑似コード
for z:
for y:
for x:
f3[x,y,z] = ...
f3.parallel(z);
//疑似コード
parallel_for z:
for y:
for x:
f3[x,y,z] = ...
//ここでjoin
Task
Queue
Worker
Worker
Worker
Fork/Join
13. 13
Schedule : split
例えばx軸を2つに分ける。
xo = x / 32;
xi = x % 32;
f3
x
y
z
//デフォルト
//疑似コード
for z:
for y:
for x:
f3[x,y,z] = ...
f3.split(z, zo, zi, 32);
//疑似コード
for zo:
for zi:
for y:
for x:
f3[x,y,zo*32+zi] = ...
z軸をzoとziにsplit
14. 14
Schedule : fuse
Splitの逆、2つの軸を一つにする。
t = y * X + x
for loop (条件分岐)は遅いのでloopを減らしてみる価値あり。
並列処理(後述)のworkを増やすのに便利。
//デフォルト
//疑似コード
for z:
for y:
for x:
f3[x,y,z] = ...
f3.fuse(x, y, t);
//疑似コード
for z:
for t:
f3[t%X,t/X,z] = ...
この計算 vs. 条件分岐
どちらが低コスト?
21. 21
Schedule : compute_at (基礎)
f2 f3
x
y
z f2.compute_at(f3,x)
f3の1画素(要素)ごとにf2の計算
を行い、結果をメモリに格納。
Cf. cpmpute_inline
f2 f3
x
y
z f2.compute_at(f3,y)
f3の1行ごとにf2の計算を行い、
結果(行)をメモリに格納。
f2 f3
x
y
z f2.compute_at(f3,z)
f3の1面ごとにf2の計算を行い、
結果(面)をメモリに格納。
22. 22
Schedule : compute_at
f2.compute_at(f3,x)
//疑似コード
for z:
for y:
バッファ f2;
for x:
//producer
for z:
for y:
for x:
f2[x,y,z] = ...
//consumer
f3[x,y,z] = ...
f2.compute_at(f3,y)
//疑似コード
for z:
バッファ f2;
for y:
//producer
for z:
for y:
for x:
f2[x,y,z] = ...
//consumer
for x:
f3[x,y,z] = ...
f2.compute_at(f3,z)
//疑似コード
バッファ f2;
for z:
//producer
for z:
for y:
for x:
f2[x,y,z] = ...
//consumer
for y:
for x:
f3[x,y,z] = ...
f3の点に必要な
f2[x,y,z]を計算
f3の線に必要な
f2[x,y,z]を計算
f3の面に必要な
f2[x,y,z]を計算
23. 23
Schedule : compute_at (応用)
f2 f3
x
y
z f3.tile(x,y,xo,yo,xi,yi,32,32)
f2.compute_at(f3,xo)
xoごとにf3のタイルに必要となるf2
の計算を行い、結果をメモリに格納。
f2 f3
x
y
z f3.split(y,yo,yi,32)
f2.compute_at(f3,yo)
f3の32行ごとに必要となるf2の計
算を行い、結果をメモリに格納。
f2 f3
x
y
z f3.tile(x,y,xo,yo,xi,yi,32,32)
f2.compute_at(f3,yo)
yoごとにf3のタイルに必要となるf2
の計算を行い、結果をメモリに格納。
f2 f3
x
y
z f3.split(x,xo,xi,32)
f3.reorder(xi,y,xo)
f2.compute_at(f3,xo)
27. 27
Schedule 例
f3のタイルを計算する際に
f1でタイルを計算 ? f2でタイルを計算 ? f3でタイルを計算
タイルのサイズを選べば画像が大きくてもcache hitを期待できる。
f1 f2 f3
x
y
z
// zを内側にしてアンロール
f3.reorder(z,x,y);
f3.unroll(z);
// タイル化
f3.tile(x,y,xo,yo,xi,yi,64,64);
f2.compute_at(f3,xo);
f1.compute_at(f3,xo);
// 更にSIMD化したい場合
f1.vectorize(xi);
f2.vectorize(xi);
f3.vectorize(xi);
ループ(条件分
岐)は遅いので
繰り返しが少な
いなら展開する。
28. 28
並列処理の時代
“The Free Lunch is Over.”
by Herb Sutter
http://www.gotw.ca/publications/concurrency-ddj.htm
並列化で頑張る時代
Halideの場合
並列化
f.parallel(軸,factor)
factor単位でtaskを作る。
SIMD化
f.vectorize(軸)
並列化
33. 33
並列schedule for cache 例
並列処理でも
適切なタイルサイズで
Local cache経由データ受け渡し
f1 f2 f3
x
y
z
// タイル化
f3.tile(x,y,xo,yo,xi,yi,64,64);
f3.fuse(xo,yo,t);
f2.compute_at(f3,t);
f1.compute_at(f3,t);
f3.parallel(t);
//疑似コード
for z:
parallel_for t:
for yi:
for xi:
for z:
for y:
for x:
f1[x,y,z] = ...
for z:
for y:
for x:
f2[x,y,z] = ...
f3[x,y,z] = ...
Task (同一thread)
Task数は多い方
が自動ロードバラ
ンスが効きやすい。
fuseでworkを増や
す。
Thread(論理CPU)
≒ 物理CPU core
45. 45
HalideとDeep Neural Network
Halide MIT
CMU
Auto Scheduling
Google
rfactor
TVM
Tensor Comprehensions
Tiramisu
Facebook
MIT
Univ. of Washington
Differentiable
Programming
Reduction計算部
(例:Σ)の並列化
自動微分の導入
Deep Neural
Network等の計算
Auto Tuning
進化的
アルゴリズム
Polyhedral
Optimization