Taichi をベースにした Python によるハイパフォーマンス コンピューティングの入門ガイド
Python プログラミング言語の誕生以来、その中心となる哲学は、コードの読みやすさと単純さを最大限に高めることでした。 Python の読みやすさとシンプルさの追求は、ほとんど狂気の沙汰です。これは 1 つの事実から確認できます。Python システムのルート ディレクトリに「import this」コマンドを入力して Enter キーを押すと、すぐに小さな英語の詩が表示されます。これを中国語に翻訳すると、おおよそ次のような意味になります。
"美しいことは醜いことよりも優れており、明示的なことは暗黙的なことよりも優れています。 単純なほうが複雑なより優れており、複雑なほうが複雑なほうが優れています。フラットなほうがネストされたよりも優れており、スパースなほうがより優れています。 読みやすさは非常に重要です...」単純さは複雑さより優れており、読みやすさは非常に重要です。 Python が実際にこれらの目標を達成するのに非常に成功していることは疑いの余地がありません。Python は学習するのに断然最もユーザーフレンドリーな言語であり、通常の Python プログラムは通常、同等の C コードよりも 5 ~ 10 倍短いです。残念ながら、そこには落とし穴があります: Python の単純さはパフォーマンスを犠牲にしています! 実際、Python プログラムは C プログラムよりも 10 ~ 100 倍遅いです。したがって、速度と単純さの間には恒久的なトレードオフが存在し、どのプログラミング言語も両方を兼ね備えることは不可能であると考えられます。 しかし、心配しないでください。すべての希望が失われるわけではありません。 Taichi は両方の長所を提供しますTaichi プログラミング言語は、汎用の高性能コンピューティングをサポートする構造で Python プログラミング言語を拡張する試みです。マルチコア CPU 機能や、さらに重要な GPU パフォーマンスなど、コンピューターのすべてのコンピューティング能力を活用しながら、Python へのシームレスな埋め込みをサポートします。 この記事では、Taichi を使用して作成したサンプル プログラムを紹介します。このプログラムは GPU を使用して、球体上に落ちる布片のリアルタイムの物理シミュレーションを実行し、同時に結果をレンダリングします。 リアルタイム GPU 物理シミュレーターを作成するのは簡単な作業ではありませんが、このルーチンを実装する Taichi ソース コードは非常にシンプルです。この記事の残りの部分では、実装全体を説明して、Taichi が提供するものと、それがいかに強力で使いやすいかを理解できるようにします。 始める前に、このプログラムが何行のコードで構成されているか推測したほうがよいでしょう。もちろん、答えは記事の最後にあります。 アルゴリズムの概要私たちのプログラムは、一枚の布を質量バネシステムとしてモデル化します。より具体的には、このクロスを点塊の N×N グリッドとして表し、隣接する点がバネで接続されています。スタンフォード大学の Matthew Fisher が提供した以下の図は、この構造を示しています。- 重力
- バネの内部力
- ダンプニング
- 真ん中に挟まれた赤いボールとの衝突
import taichi as ti
ti.init(arch=ti.cuda)
ti.init(arch=ti.cpu)
N = 128 x = ti.Vector.field(3, float, (N, N)) v = ti.Vector.field(3, float, (N, N))
ball_radius = 0.2 ball_center = ti.Vector.field(3, float, (1,))
def init_scene(): for i, j in ti.ndrange(N, N): x[i, j] = ti.Vector([i * cell_size, j * cell_size / ti.sqrt(2), (N - j) * cell_size / ti.sqrt(2)]) ball_center[0] = ti.Vector([0.5, -0.5, 0.0])
模拟
在每个时间步中,我们的程序都会模拟影响布料运动的4个因素:重力、弹簧内力、阻尼和与红球的碰撞。其中,重力是最容易处理的。
下面是实现这一点的代码:
@ti.kernel def step(): for i in ti.grouped(v): v[i].y -= gravity * dt
这里有两点需要注意。首先,语句for i in ti.grouped(x)意味着将循环迭代x的所有元素,而不管x中有多少维度。其次,也是最重要的是:注解@ti.kernel意味着Taichi将自动并行运行函数中的任何顶级for循环。在本例中,Taichi将并行更新v中每个N*N向量的y分量。
接下来,我们来处理弦线的内力计算问题。首先,请注意前面图形中的每个质点最多连接到八个邻接质点。这些连接在我们的程序中表示如下:
links = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [1, -1], [-1, 1], [1, 1] links = [ti.Vector(v) for v in links]
从物理角度来看,系统中的每个弹簧s都用固定长度l(s,0)初始化。在任何时间t,如果s的当前长度l(s,t)超过l(s,0),则弹簧将在其端点上施加力,将它们拉在一起。相反,如果l(s,t)小于l(s,0),则弹簧会将端点彼此推开。这些力的大小始终与l(s,0)-l(s,0)的绝对值成正比。此交互由以下代码段捕获:
for i in ti.grouped(x): force = ti.Vector([0.0,0.0,0.0]) for d in ti.static(links): j = min(max(i + d, 0), [N-1,N-1]) relative_pos = x[j] - x[i] current_length = relative_pos.norm() original_length = cell_size * float(i-j).norm() if original_length != 0: force +=stiffness * relative_pos.normalized() * (current_length - original_length) / original_length v[i] +=force * dt
请注意,这个for循环仍应作为substep函数中的顶级for循环,该函数用@ti.kernel注解。这样可以确保并行计算施加到每个质点的弹簧力。stiffness在此是一个常数,用于控制弹簧长度变化的程度。在上述程序中,我们使用stiffness =1600指定它的值。在现实世界中,当弹簧振动时,弹簧中储存的能量会消散到周围环境中,其振动最终停止。为了捕捉这种效应,在每个时间步,我们稍微降低每个点的速度大小:
for i in ti.grouped(x): v[i] *= ti.exp(-damping * dt)
在此,damping取固定值2。
我们还需要处理布料和红球之间的碰撞。要做到这一点,我们只需将质点与球接触时的速度降低到0。这样可以确保布料“挂”在球上,而不是穿透球或向下滑动:
if (x[i]-ball_center[0]).norm() <= ball_radius: v[i] = ti.Vector([0.0, 0.0, 0.0])
最后,我们用每个质点的速度更新其自身的位置:
x[i] += dt * v[i]
这就是我们对一块质量弹簧布料进行并行模拟所需的全部代码。
渲染
我们将使用Taichi内置的基于GPU的GUI系统(昵称是“GGUI”)渲染布料。GGUI使用Vulkan图形API进行渲染,因此请确保您的计算机上安装了Vulkan(https://docs.taichi.graphics/lang/articles/misc/ggui)。GGUI支持渲染两种类型的3D对象:三角形网格和粒子。在我们的示例中,将把布料渲染为三角形网格,把红色球渲染为单个粒子。
GGUI表示一个三角形网格,包含两个Taichi场:一个顶点(vertices)场和一个索引(indices)场。顶点场是一个一维场,其中每个元素提取是一个表示顶点位置的三维向量,可能由多个三角形共享。在我们的应用程序中,每个点质量都是一个三角形顶点,因此我们可以简单地将数据从x复制到vertices:
vertices = ti.Vector.field(3, float, N * N) @ti.kernel def set_vertices(): for i, j in ti.ndrange(N, N): vertices[i * N + j] = x[i, j]
请注意,每一帧都需要调用set_vertices,因为顶点位置不断被模拟更新。
我们的布料是用一个质点的N×N网格表示,也可以被看作一个由(N-1)×(N-1)小正方形组成的网格。每个正方形都将渲染为两个三角形。因此,总共有(N-1)×(N-1)×2个三角形。每个三角形将在顶点场中表示为3个整数,该场记录顶点场中三角形顶点的索引。以下代码片段捕获了这一结构:
num_triangles = (N - 1) * (N - 1) * 2 indices = ti.field(int, num_triangles * 3) @ti.kernel def set_indices(): for i, j in ti.ndrange(N, N): if i < N - 1 and j < N - 1: square_id = (i * (N - 1)) + j #正方形的第一个小三角形 indices[square_id * 6 + 0] = i * N + j indices[square_id * 6 + 1] = (i + 1) * N + j indices[square_id * 6 + 2] = i * N + (j + 1) #正方形的第二个小三角形 indices[square_id * 6 + 3] = (i + 1) * N + j + 1 indices[square_id * 6 + 4] = i * N + (j + 1) indices[square_id * 6 + 5] = (i + 1) * N + j
请注意,与函数set_vertices不同,函数set_indices只需要调用一次。这是因为三角形顶点的索引实际上并没有改变——只是位置在改变。
为了将红球渲染为粒子,我们实际上不需要准备任何数据,我们之前定义的ball_center和ball_radius变量就是GGUI所需要的全部内容。
完整代码
至此,我们已经介绍完本文示例程序的所有核心函数!下面代码展示了我们如何调用这些函数:
init() set_indices() window = ti.ui.Window("Cloth", (800, 800), vsync=True) canvas = window.get_canvas() scene = ti.ui.Scene() camera = ti.ui.make_camera() while window.running: for i in range(30): step() set_vertices() camera.position(0.5, -0.5, 2) camera.lookat(0.5, -0.5, 0) scene.set_camera(camera) scene.point_light(pos=(0.5, 1, 2), color=(1, 1, 1)) scene.mesh(vertices, indices=indices, color=(0.5, 0.5, 0.5), two_sided = True) scene.particles(ball_center, radius=ball_radius, color=(0.5, 0, 0)) canvas.scene(scene) window.show()
需要注意的一个小细节是,我们将在主程序循环中的每一帧调用函数step()30次,而不是调用一次。这样做的目的就是让动画不会运行得太慢。把上述所有代码放在一起,整个程序应该是这样的:
import taichi as ti ti.init(arch=ti.cuda) # 另一种可选择方案: ti.init(arch=ti.cpu) N = 128 cell_size = 1.0 / N gravity = 0.5 stiffness = 1600 damping = 2 dt = 5e-4 ball_radius = 0.2 ball_center = ti.Vector.field(3, float, (1,)) x = ti.Vector.field(3, float, (N, N)) v = ti.Vector.field(3, float, (N, N)) num_triangles = (N - 1) * (N - 1) * 2 indices = ti.field(int, num_triangles * 3) vertices = ti.Vector.field(3, float, N * N) def init_scene(): for i, j in ti.ndrange(N, N): x[i, j] = ti.Vector([i * cell_size , j * cell_size / ti.sqrt(2), (N - j) * cell_size / ti.sqrt(2)]) ball_center[0] = ti.Vector([0.5, -0.5, -0.0]) @ti.kernel def set_indices(): for i, j in ti.ndrange(N, N): if i < N - 1 and j < N - 1: square_id = (i * (N - 1)) + j # 1st triangle of the square indices[square_id * 6 + 0] = i * N + j indices[square_id * 6 + 1] = (i + 1) * N + j indices[square_id * 6 + 2] = i * N + (j + 1) # 2nd triangle of the square indices[square_id * 6 + 3] = (i + 1) * N + j + 1 indices[square_id * 6 + 4] = i * N + (j + 1) indices[square_id * 6 + 5] = (i + 1) * N + j links = [[-1, 0], [1, 0], [0, -1], [0, 1], [-1, -1], [1, -1], [-1, 1], [1, 1]] links = [ti.Vector(v) for v in links] @ti.kernel def step(): for i in ti.grouped(x): v[i].y -= gravity * dt for i in ti.grouped(x): force = ti.Vector([0.0,0.0,0.0]) for d in ti.static(links): j = min(max(i + d, 0), [N-1,N-1]) relative_pos = x[j] - x[i] current_length = relative_pos.norm() original_length = cell_size * float(i-j).norm() if original_length != 0: force +=stiffness * relative_pos.normalized() * (current_length - original_length) / original_length v[i] +=force * dt for i in ti.grouped(x): v[i] *= ti.exp(-damping * dt) if (x[i]-ball_center[0]).norm() <= ball_radius: v[i] = ti.Vector([0.0, 0.0, 0.0]) x[i] += dt * v[i] @ti.kernel def set_vertices(): for i, j in ti.ndrange(N, N): vertices[i * N + j] = x[i, j] init_scene() set_indices() window = ti.ui.Window("Cloth", (800, 800), vsync=True) canvas = window.get_canvas() scene = ti.ui.Scene() camera = ti.ui.make_camera() while window.running: for i in range(30): step() set_vertices() camera.position(0.5, -0.5, 2) camera.lookat(0.5, -0.5, 0) scene.set_camera(camera) scene.point_light(pos=(0.5, 1, 2), color=(1, 1, 1)) scene.mesh(vertices, indices=indices, color=(0.5, 0.5, 0.5), two_sided = True) scene.particles(ball_center, radius=ball_radius, color=(0.5, 0, 0)) canvas.scene(scene) window.show()
注意到,上述代码总行数仅有91行!
挑战任务
我希望你喜欢本文中提供的上述示例程序!如果的确如此,下面几个不同挑战等级的任务留给你:
- [簡単] パラメータを気軽に調整します。剛性、減衰、dt パラメータを変更すると、プログラムの動作がどのように変化するかを観察します。
- [簡単] プログラム内の vsync=True を vsync=False に変更します。これにより、プログラムの 60 フレーム/秒の制限が解除され、プログラムがマシン上でどのように実行されるかを監視します。
- 【中難易度】布とボールの間の少し複雑な相互作用を実現します。布を貫通せずにボールの上を滑り落ちます。
- 【中難易度】ボールを追加: 布を複数のボールと相互作用させます。
- 【難易度上級】2 番目の課題を完了したら、Taichi を使用せずに、同じプログラムを別のプログラミング言語または Python で実装してみます。取得できる最大 FPS (1 秒あたりのフレーム数) と、同様のパフォーマンスを得るために記述する必要があるコードの量を観察します。
まとめ
最後に、Taichi によって上記の 91 行の Python コードで実装できるようになった内容を確認してみましょう。10,000 個の質点と約 100,000 個のバネを備えた質量バネ システムです。
- @ti.kernel アノテーションを使用して、CUDA GPU または CPU 上のマルチスレッドを介してシミュレーションを自動的に並列化します
- GPU レンダラーを介してリアルタイムで結果をレンダリングします
- Taichi notこれにより、これらすべての複雑な関数を少量のコードで実装できるようになり、CUDA、マルチスレッド プログラミング、または GPU レンダリングを学習する手間が省けます。 Taichi を使えば誰でも高性能なプログラムを書くことができます。コードのアルゴリズムの側面に焦点を当て、パフォーマンスの側面はプログラミング言語自体に任せることができます。これにより、Taichi のモットーである「並列プログラミングをすべての人に!
Github ページ
にアクセスしてください。詳細なドキュメントと Taichi プロジェクトの多くの例が見つかり、どれも興味深いものです。最後に、並列コンピューティング用のフレンドリーで強力な言語を開発するという使命を信じているのであれば、オープンソースのコントリビューターとして Taichi に参加することを大歓迎です。 翻訳者紹介Zhu Xianzhong 氏、51CTO コミュニティー編集者、51CTO エキスパートブロガー、講師、濰坊の大学のコンピューター教師、そして大学のベテランフリーランスのプログラミング業界。初期の頃は、さまざまな Microsoft テクノロジに焦点を当てていました (ASP.NET AJX および Cocos 2d-X に関連する 3 冊の技術書籍を編集しました)。過去 10 年間は、オープンソースの世界に専念してきました (人気のある完全なソースに精通しています)。スタックWeb開発技術)を学び、OneNet/AliOS Arduino/ESP32/Raspberry PiなどのIoT開発技術やScala Hadoop Spark Flinkなどのビッグデータ開発技術について学びました。 原題: A Beginner's Guide to High-Performance Computing in Python、著者: Dunfan Lu以上がTaichi をベースにした Python によるハイパフォーマンス コンピューティングの入門ガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









スキルや業界のニーズに応じて、PythonおよびJavaScript開発者には絶対的な給与はありません。 1. Pythonは、データサイエンスと機械学習でさらに支払われる場合があります。 2。JavaScriptは、フロントエンドとフルスタックの開発に大きな需要があり、その給与もかなりです。 3。影響要因には、経験、地理的位置、会社の規模、特定のスキルが含まれます。

明確で明確なものは区別に関連していますが、それらは異なる方法で使用されます。明確な(形容詞)は、物事自体の独自性を説明し、物事の違いを強調するために使用されます。明確な(動詞)は、区別の動作または能力を表し、差別プロセスを説明するために使用されます。プログラミングでは、個別は、重複排除操作などのコレクション内の要素の独自性を表すためによく使用されます。明確なは、奇数や偶数の偶数を区別するなど、アルゴリズムまたは関数の設計に反映されます。最適化する場合、異なる操作は適切なアルゴリズムとデータ構造を選択する必要がありますが、異なる操作は、論理効率の区別を最適化し、明確で読み取り可能なコードの書き込みに注意を払う必要があります。

H5ページは、コードの脆弱性、ブラウザー互換性、パフォーマンスの最適化、セキュリティの更新、ユーザーエクスペリエンスの改善などの要因のため、継続的に維持する必要があります。効果的なメンテナンス方法には、完全なテストシステムの確立、バージョン制御ツールの使用、定期的にページのパフォーマンスの監視、ユーザーフィードバックの収集、メンテナンス計画の策定が含まれます。

!X理解!Xは、C言語の論理的な非操作者です。 Xの値をブーリングします。つまり、虚偽の真の変化、trueへの誤った変更です。ただし、Cの真実と虚偽はブール型ではなく数値で表されていることに注意してください。非ゼロは真であると見なされ、0のみが偽と見なされます。したがって、!xは正の数と同じ負の数を扱い、真実と見なされます。

Cには組み込みの合計関数はありませんが、次のように実装できます。ループを使用して要素を1つずつ蓄積します。ポインターを使用して、要素に1つずつアクセスして蓄積します。大量のデータ量については、並列計算を検討してください。

クロール中に58.com作業ページの動的データを取得するにはどうすればよいですか? Crawlerツールを使用して58.comの作業ページをrawったら、これに遭遇する可能性があります...

コードのコピーと貼り付けは不可能ではありませんが、注意して扱う必要があります。コード内の環境、ライブラリ、バージョンなどの依存関係は、現在のプロジェクトと一致しないため、エラーや予測不可能な結果が得られます。ファイルパス、従属ライブラリ、Pythonバージョンなど、コンテキストが一貫していることを確認してください。さらに、特定のライブラリのコードをコピーして貼り付けるときは、ライブラリとその依存関係をインストールする必要がある場合があります。一般的なエラーには、パスエラー、バージョンの競合、一貫性のないコードスタイルが含まれます。パフォーマンスの最適化は、コードの元の目的と制約に従って再設計またはリファクタリングする必要があります。コピーされたコードを理解してデバッグすることが重要であり、盲目的にコピーして貼り付けないでください。

PSの「読み込み」の問題は、リソースアクセスまたは処理の問題によって引き起こされます。ハードディスクの読み取り速度は遅いか悪いです。CrystaldiskInfoを使用して、ハードディスクの健康を確認し、問題のあるハードディスクを置き換えます。不十分なメモリ:高解像度の画像と複雑な層処理に対するPSのニーズを満たすためのメモリをアップグレードします。グラフィックカードドライバーは時代遅れまたは破損しています:ドライバーを更新して、PSとグラフィックスカードの間の通信を最適化します。ファイルパスが長すぎるか、ファイル名に特殊文字があります。短いパスを使用して特殊文字を避けます。 PS独自の問題:PSインストーラーを再インストールまたは修理します。
