3
4

CUDA GPU を使った 3次元でのシミュレーション。

Last updated at Posted at 2024-08-08

ショートストーリー: 「東京のプログラマーとテンソルの解法。」

東京のビル群が夜空にきらめく中、ケンジは自分のデスクに向かって深く考え込んでいた。彼は東京の一流IT企業でプログラマーとして働いており、複雑なデータの解析とシミュレーションを専門にしていた。最近、彼は大きな課題に直面していた。それは、三次元行列、つまりテンソル形式のデータの処理だった。

animation.gif

「二次元の行列は普通のコンピューターでもシミュレーションが可能だけど、三次元になるとまったく違う。」ケンジは自分に言い聞かせながら、モニターの前でため息をついた。三次元行列のシミュレーションは、気象予測や流体力学、その他の現実世界のシミュレーションに必要なものであり、非常に複雑で計算量が膨大だ。通常のコンピューターでは、処理が追いつかず、時間がかかりすぎてしまう。

以前、GPUによる高速化は専門的な知識が必要で、カーネルコードを書くのには多くのコストがかかっていた。しかし、ケンジは今、CUPYという強力なライブラリを使うことで、その障壁を乗り越えられることを知っていた。CUPYは、通常のPythonコードを書くだけでGPUの計算を行えるようにしてくれるライブラリであり、GPUの並列処理を簡単に利用できるのだった。

「これで、三次元行列の計算を効率的に処理できるはずだ。」ケンジは自信を持ってコードを書き始めた。彼の目標は、メッシュグリッドを利用して三次元行列の計算を配列操作として表現し、高速な計算を実現することだった。メッシュグリッドを用いることで、複雑な三次元行列の計算が全ての格子点にそれぞれのスレッドを起動し同時並列計算で一気に効率的に行えると信じていた。

ケンジはまず、メッシュグリッドを作成し、これを使って三次元空間のデータを生成するコードを実装した。その後、CUPYを使用してGPUでの計算を実行した。CUPYのシンプルなAPIによって、彼はGPUの計算力を手軽に活用することができ、以前のような複雑なカーネルコードの記述をせずに済んだ。数時間の作業の末、最初のテストが終了し、結果は驚くべきものであった。処理速度が劇的に向上し、膨大なデータが瞬時に計算される様子に感動した。

「これでどうだ!」ケンジは歓声を上げた。メッシュグリッドを用いた計算が、GPU上での高速処理を可能にし、気象予測や流体力学のシミュレーションが現実的な速度で行えるようになった。テンソルの計算が、GPUの並列処理能力を活用することで、精度と効率が格段に向上したのだ。

3d_sine_wave_animation.gif

夜の東京が静かに時を刻む中、ケンジは自分のデスクに座りながら、ガラス窓越しに都市の夜景を眺めた。彼の心の中には、テンソルの謎を解決するために挑んだ冒険が色鮮やかに広がっていた。メッシュグリッドを使用した計算の解放により、より高精度で迅速なシミュレーションが実現し、現実世界の複雑な現象をより深く理解するための鍵が開かれたことを、彼は確信していた。

ケンジは、次なる挑戦に向けて静かに胸を張り、未来への期待に胸を膨らませながら、静かに微笑んだ。テンソルの計算が解放され、GPUによる高速な計算が現実世界のシミュレーションをよりリアルにする未来に思いを馳せた。CUPYの導入によって、GPUのパワーを簡単に活用できるようになり、複雑な計算がより手軽に、効率的に行えるようになったことを、彼は心から喜んでいた。

4D Cupy の説明。

cupy.linspace、cupy.meshgridを使ってGPU上でメッシュグリッドを生成します。
update関数内でサイン波の計算をGPU上で行い、cupy配列として計算します。
プロットのために、cupy配列をnumpy配列に変換しています (cp.asnumpy() を使用)。

3D CPU numpy.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from mpl_toolkits.mplot3d import Axes3D

# ダミーデータの生成
def generate_data(t):
    x = np.linspace(-5, 5, 10)
    y = np.linspace(-5, 5, 10)
    X, Y = np.meshgrid(x, y)
    Z = np.sin(np.sqrt(X**2 + Y**2) + t)
    return X, Y, Z

# アニメーションの更新関数
def update(frame):
    ax.clear()
    X, Y, Z = generate_data(frame * 0.1)
    ax.plot_surface(X, Y, Z, cmap='viridis')
    ax.set_title(f"Time = {frame * 0.1:.2f}")

# グラフの設定
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# アニメーションの作成
ani = FuncAnimation(fig, update, frames=100, interval=100, repeat=True)

# GIFファイルとして保存
ani.save('animation.gif', writer='pillow', fps=10)

plt.show()

4D CPU numpy.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import PillowWriter, FuncAnimation
from mpl_toolkits.mplot3d import Axes3D

# パラメータ設定
width, height, depth = 20, 20, 20  # 空間のサイズ
frames = 60  # フレーム数

# 初期範囲
x_range = (-2.0, 2.0)
y_range = (-2.0, 2.0)
z_range = (-2.0, 2.0)

# メッシュグリッドを生成
x = np.linspace(x_range[0], x_range[1], width)
y = np.linspace(y_range[0], y_range[1], height)
z = np.linspace(z_range[0], z_range[1], depth)
X, Y, Z = np.meshgrid(x, y, z, indexing='ij')

# アニメーションの更新関数
def update(frame):
    plt.clf()
    ax = fig.add_subplot(111, projection='3d')

    # サイン関数で変化する値を計算
    value = np.sin(X + frame * 0.1) * np.cos(Y + frame * 0.1) * np.sin(Z + frame * 0.1)

    # 値をnumpy配列に変換
    value_np = value

    # 各座標点の色を計算
    norm = plt.Normalize(value_np.min(), value_np.max())
    colors = plt.cm.viridis(norm(value_np.flatten()))

    # 3次元散布図としてプロット
    ax.scatter(X.flatten(), Y.flatten(), Z.flatten(), c=colors, marker='o')

    # プロットの設定
    ax.set_xlim(x_range)
    ax.set_ylim(y_range)
    ax.set_zlim(z_range)
    ax.set_title(f'Frame: {frame}')

# アニメーション生成
fig = plt.figure()
ani = FuncAnimation(fig, update, frames=frames, repeat=False)
writer = PillowWriter(fps=10)
ani.save("3d_sine_wave_animation.gif", writer=writer)

plt.show()

4D Cupy GPU.

説明
メッシュグリッドの生成:

cp.meshgridを使用して、3次元空間のX、Y、Z座標のメッシュグリッドを生成します。これは、各座標点の位置を定義するための3次元配列を作成します。

サイン関数による値の計算:

各フレームで、X, Y, Z座標に基づいてサイン関数を適用し、時間(フレーム数)に応じて値が変化するようにします。

値の色を計算:

matplotlibのカラーマップ機能を使用して、計算された値を色に変換します。ここではviridisカラーマップを使用しています。

3次元プロット:

各フレームごとに、3次元散布図としてプロットし、色によって値の違いを表現します。

アニメーションの生成:

FuncAnimationを使用して、指定したフレーム数にわたってアニメーションを生成し、GIFとして保存します。

このコードにより、3次元空間内の各点がサイン関数によって時間とともに変化し、その変化を色で表現するアニメーションを作成できます。

# 必要なライブラリのインストールコマンド
# !pip install cupy numpy

import cupy as cp
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import PillowWriter, FuncAnimation
from mpl_toolkits.mplot3d import Axes3D

# パラメータ設定
width, height, depth = 20, 20, 20  # 空間のサイズ
frames = 60  # フレーム数

# 初期範囲
x_range = (-2.0, 2.0)
y_range = (-2.0, 2.0)
z_range = (-2.0, 2.0)

# メッシュグリッドを生成
x = cp.linspace(x_range[0], x_range[1], width)
y = cp.linspace(y_range[0], y_range[1], height)
z = cp.linspace(z_range[0], z_range[1], depth)
X, Y, Z = cp.meshgrid(x, y, z, indexing='ij')

# アニメーションの更新関数
def update(frame):
    plt.clf()
    ax = fig.add_subplot(111, projection='3d')

    # サイン関数で変化する値を計算 (GPU上で計算)
    value = cp.sin(X + frame * 0.1) * cp.cos(Y + frame * 0.1) * cp.sin(Z + frame * 0.1)

    # 値をnumpy配列に変換
    value_np = cp.asnumpy(value)

    # 各座標点の色を計算
    norm = plt.Normalize(value_np.min(), value_np.max())
    colors = plt.cm.viridis(norm(value_np.flatten()))

    # 3次元散布図としてプロット
    ax.scatter(cp.asnumpy(X).flatten(), cp.asnumpy(Y).flatten(), cp.asnumpy(Z).flatten(), c=colors, marker='o')

    # プロットの設定
    ax.set_xlim(x_range)
    ax.set_ylim(y_range)
    ax.set_zlim(z_range)
    ax.set_title(f'Frame: {frame}')

# アニメーション生成
fig = plt.figure()
ani = FuncAnimation(fig, update, frames=frames, repeat=False)
writer = PillowWriter(fps=10)
ani.save("3d_sine_wave_animation.gif", writer=writer)

plt.show()


3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4