以下の内容はhttps://np2lkoo.hatenablog.com/entry/2021/11/27/230435より取得しました。


Pythonで複素数計算

気になるのは処理速度ですが

こんにちわ、こんばんわ。かえるのクーの助手の「井戸中 聖」(いとなか セイ)でございます。

Amazon.co.jp | スペシャルウィーク 駆け抜けた王道 [DVD] DVD・ブルーレイ - 競馬  Amazon | ハルウララ [DVD] | 映画

今は複素数を勉強中です。果たして計算は速いのでしょうか?

速い?遅い?

pythonで複素数は普通の実数とほぼ同じように扱えることは確認しましたが、計算速度が遅くならないか確認しました。

結果は(わたくし的には)全く問題ありませんでした。

実数より情報量が2倍になるので、計算時間は実数より確実に増えますが、概ね2倍以内に収まっていました。(四則演算、ドット計算)

厳密な測定をしていないので、結果は貼りませんが、速度的に全く問題なく扱えることを確認しました。(追記:cupyを最新化できたので、結局測定しました!)

(現時点で確認しているのはcmath と numpyです。cupyは最新にしようとして失敗して環境を壊してしまったので、今回は諦めます。)

pythonで複素数を扱うには、こちらの説明が分かりやすかったです。

どうもありがとうございます。

自己符号化器はdot計算が重要なポイントですが、numpy.vdotを使わないといけないのですね!大変勉強になりました。知らないと絶対「ハマる」ところです!!

この週末は、自己符号化器を大改造する前に、純粋に値を複素数にしてみてうまく動作するのかをやってみます。

でも、もしかしたら忙しくて見れていなかった「アニメ」を一気見するかもしれません。あしからず。

追伸:速度計測結果(2021/11/28)

cupy のインストール失敗と思っていたのは、ローカルでフルコンパイルしようとしてのエラーだったようです。バイナリ/コンパイル済パッケージを導入して問題なく動作できました。そこで、時間計測を貼ることにします。(新しいページをつくるまでもない話題なので、こちらに追記します)

べたべたですが、計測プログラムを貼ります。


#! /usr/bin/python
# -*- coding: utf-8 -*-
import time
import cmath #今回の範囲では使用せず
import numpy as np
import cupy as cp

""" 複素数の計算速度測定/実数計算との差異
"""

def print_proc_time(f):
def print_proc_time_func(*args, **kwargs):
start_time = time.perf_counter()
return_val = f(*args, **kwargs)
end_time = time.perf_counter()
elapsed_time = end_time - start_time
print(f.__name__, elapsed_time)
return return_val

return print_proc_time_func

@print_proc_time
def calc_mass(n, m):
x = 0.0
for ii in range(n):
for jj in range(m):
x += ii + jj
x *= (0.1 + 0.1)
#print(x)

@print_proc_time
def calc_cmass(n, m):
x = 0.0 + 0j
for ii in range(n):
for jj in range(m):
x += ii + jj * 1j
x *= (0.1 + 0.1j)
#print(x)

@print_proc_time
def set_cnumpy(n, m):
real = np.random.rand(n, m)
img = np.random.rand(n, m) * 1j
comp = real + img
return comp

@print_proc_time
def set_rnumpy(n, m):
real = np.random.rand(n, m)
img = np.random.rand(n, m) # real
r = real + img
return r

@print_proc_time
def dot_numpy(cnum, cnumt):
y = np.dot(cnum, cnumt)
return y

@print_proc_time
def vdot_numpy(cnum, cnumt):
y = np.vdot(cnum, cnumt)
return y

@print_proc_time
def dot_cupy(cnum, cnumt):
y = cp.dot(cnum, cnumt)
return y

@print_proc_time
def vdot_cupy(cnum, cnumt):
y = cp.vdot(cnum, cnumt)
return y

#時間計測
# 通常計算
calc_mass(13000, 13000)
calc_cmass(13000, 13000)
# numpy配列計算
rnum = set_rnumpy(13000, 13000)
rnumt = rnum.T # 転置するのはとくに意味がありません。異なる配列扱いにしたかっただけです。
dotrnum = dot_numpy(rnum, rnumt) # 比較用実数 dot計算(numpy)
#print(dotrnum)
cnum = set_cnumpy(13000, 13000)
cnumt = cnum.T
vdotnum = vdot_numpy(cnum, cnumt) # 虚数 vdot計算(numpy)
#print(vdotnum)
rcp = cp.asarray(rnum)
rcpt = rcp.T
dotrcp = dot_cupy(rcp, rcpt) # 比較用実数 dot計算(cupy)
#print(dotrcp)
ccp = cp.asarray(cnum)
ccpt = ccp.T
vdotcp = vdot_cupy(ccp, ccpt) # 虚数 vdot計算
#print(vdotcp)

結果です

calc_mass 11.4962692
calc_cmass 18.3728862
set_rnumpy 2.5951954000000015
dot_numpy 4.6389666999999974
set_cnumpy 3.8343433000000005
vdot_numpy 3.680981799999998
dot_cupy 1.0273730999999984
vdot_cupy 24.810232099999993

Process finished with exit code 0

とっても意外だったのは、cupyの vdot 計算が異常に遅かったこと&vdotの計算精度が本家 numpyと異なるようで(無視できない!誤差程度で)計算結果に差異がありました。dot/vdot 計算は自己符号化器の計算では多用するので、当面複素数計算はnumpyで行うことになると思います。numpyのdot/vdot計算では全core/スレッド総動員で計算して、あまり音をたてて回ることのないCPUファンがほぼフル回転しています。

なお、参考までに、実験で使用したPCのスペックは

CPUはcore i9 9940X(14core/28Tread)/96GB 、GPUはRTX3060(12GB)です。

藤井4冠のような最高スペックPCが欲しい!です!!

Vdot系計算はおそらくreduction計算が多く、GPUは苦手なのだと思いますが、numpyのvdot計算が異常に速いので、まだまだ改善の余地があると思います。Preferrd Networks様の底力でcupyのvdot計算をなんとかしてください!よろしくお願いいたします。

(さらに追記/編集)

気になってcupyのソース見てみましたが、利用しているMAGMA(Matrix Algebra on GPU and Multicore Architectures:テネシー大学製の汎用GPU/マルチコア用のライブラリ)のロジックを使っているようでした。cythonでカーネルをコーディングしている部分はあるので、このあたりをnumpyの並列処理とロジック互換にすれば改善できる気がします。がんばってください。numpyのソースもついでに見てみましたが、とっても興味深いです。おもしろそうです。道草したいのをぐっとこらえます。

マグマ (バンド) - Wikipedia(この前BSでMAGMAの2018ライブを放送していて驚きました)

みんなでコバイア語をマスターしよう!




以上の内容はhttps://np2lkoo.hatenablog.com/entry/2021/11/27/230435より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14