GPUは、多数のスレッドに同じ計算をさせる装置
GPU(ジーピーユー)とは、とても多くの小さなスレッドに、同じ計算を同時にさせる装置です。スレッドはブロックにまとめられ、ブロックが集まってグリッドになります。
このレッスンでは、この3つの段の数え方と、各スレッドが自分の担当を知る方法を学びます。ラボにGPUはなく、起動はPythonで真似ます。
このレッスンのゴール
メモ
ブロックの番号とスレッドの番号から、そのスレッドが担当する要素の番号を求められる。
重要な言葉
| ことば | いみ | れい |
|---|---|---|
| スレッド | GPUで動く、とても小さな1つの流れ | |
| ブロック | いくつかのスレッドをまとめた組 | |
| グリッド | 起動したブロック全部の集まり | |
| ブロックの大きさ | 1つのブロックにあるスレッドの数 | block_dim |
| グローバルな番号 | 全スレッドの中での、通し番号 |
学生が入力するセルは、このプレビューでは空白です。
スレッドはブロックに、ブロックはグリッドに入る
GPUに仕事を頼むことを、起動と呼びます。起動では、ブロックの数と、1ブロックのスレッドの数を決めます。
たとえば、10個の値段を処理するのに、4スレッドのブロックを3つ起動します。スレッドは全部で12個です。
10個の値段に、3ブロック×4スレッド
| 段 | 数え方 | この例 |
|---|---|---|
| グリッド | ブロックの数 | 3ブロック |
| ブロック | 1ブロックのスレッドの数 | 4スレッド |
| スレッド全部 | 3 × 4 | 12個 |
| 要素 | 処理したいデータの数 | 10個 |
| 何もしないスレッド | 12 − 10 | 2個 |
学生が入力するセルは、このプレビューでは空白です。
スレッドは、自分の番号を計算で知る
全部のスレッドは同じプログラムを走らせます。違うのは、ブロックの番号とスレッドの番号だけです。
担当する要素の番号は、ブロックの番号 × ブロックの大きさ + スレッドの番号です。ブロック2のスレッド3なら、2 × 4 + 3 で11番です。
スレッドの担当する番号を出す
# ブロックの大きさ4で、スレッドが担当する要素の番号を出します。
block_dim = 4
for block_idx in range(3):
for thread_idx in range(block_dim):
index = block_idx * block_dim + thread_idx
print("ブロック", block_idx, "スレッド", thread_idx, "-> 番号", index)
# block_dim を 3 に変えて、番号の並びを見ましょう。
よくある間違い
注意
スレッドの番号だけで、担当する要素が決まると思いがちです。ブロックごとにスレッドの番号は0から数え直します。ブロックの番号と大きさを使った、通し番号の計算が要ります。
ラボの端末で、起動の様子を見る
ラボにGPUはありません。スクリプトは、3ブロック×4スレッドの起動を、Pythonで真似ます。出力には英語の単語が出ます。
block はブロックの番号、thread はスレッドの番号、global index が通し番号です。10個を超えた番号のスレッドは、何もしません。
起動の様子を見る
docker exec jupyter python3 steps/kernel.pyここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
通し番号を1つ計算する
docker exec jupyter python3 -c "print(2 * 4 + 3)"ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
さらに挑戦: ブロックの大きさを選ぶ
100個の要素を、ブロックの大きさ32で覆うと、ブロックはいくつ要るでしょうか。何もしないスレッドは、いくつ出るでしょうか。
ブロックの大きさを大きくすると、何もしないスレッドは増えるでしょうか。自分の言葉で説明しましょう。