質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

5371閲覧

以下のコードが遅いため、速くしたいです。

yumatsuoka

総合スコア7

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

4クリップ

投稿2017/12/23 03:45

編集2017/12/23 04:08

###前提・実現したいこと
PythonのNumpyを使って、大型のテンソルを処理しようとしています。
下記のものが自分で書いたコードになりますが、
処理速度が遅いために、みなさんにより処理速度の速い書き方を教わりたいと思い、相談いたします。

行列を使ってやりたいことを以下に書きます。
xnという100個のデータの集合の4次元のテンソルがあり、
xnの100個それぞれのデータに対してtnというラベルが対応して振られています。

tnは0〜9までの数がランダムに100個入っており、含まれてない数もあれば、重複している数もあります。

# **tnとpyは0〜9までの数がランダムに100個入っており、含まれてない数もあれば、重複している数もあります。** tn -> [9, 2, 1, 5,...i..1] xn -> [[[[0.1, ..... 0.2], [...]], [[...], [...]]], [[[0.1, ..... 0.2], [...]], [[...], [...]]]] py -> [1, 3, 8, 2,...i..3]

また、pyというtnと同じ100次元のラベルのベクトルがあります。
そこで、pyに対して、tnとのラベルの値を基準として2つのラベルの対応を崩さない状態で状態で、
xnから(25, 250, 250)のテンソルをランダムにピックアップしたいのです。

この条件で自分が書いたコードが以下のものになります。

# versions: python=v3.6.1, numpy=v1.12.1 import numpy as np xn = np.ndarray # xn.shape => (100, 25, 250, 250) tn = np.ndarray # tn.shape => (100) py = np.ndarray # py.shape => (100) for n in range(50000): ansr = np.asarray([xn[np.random.choice(np.where(tn == y)[0], 1, replace=True)[0]] for y in py])

###解決したいこと、聞きたいこと。

上記ように処理を50,000回ほど繰り返す必要があるのですが、
上記のコードがボトルネックになっていて、処理速度がとても遅いです。

PythonのNumpyを使う前提で、上記のゴールを達成するできるだけ速いコードの書き方を提案してもらえないでしょうか。

どうぞよろしくお願いします。

###補足情報(言語/FW/ツール等のバージョンなど)

versions

  • python=3.6.1
  • numpy=1.12.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

訂正:ご指摘によりコードの間違いを訂正しました。
誤:ansr = np.asarray([xn[rd.choice(indices, replace=True)] for y in py])
正:ansr = np.asarray([xn[rd.choice(indices[y], replace=True)] for y in py])
一応速度を測りなおしたのでそれも反映しました。(割と変動するのであくまで参考値ですが)
ご指摘ありがとうございました。>mkgreiさん


素朴な点だけ・・・

ループの中で同じ計算を何度も繰り返せば効率は下がるので同一の式をループの外に移動させてはいかがですか?np.where(tn == y)[0]は何度も計算する必要はないので外に出せると思います。

またどのくらい違いがあるかわかりませんが、choiceの結果を1要素の一次元配列として取り出しその要素を取り出すぐらいなら最初からsize=Noneのままにしてはいかがでしょうか?

python

1import numpy as np 2from numpy import random as rd 3import time 4 5tn = rd.choice(10, 100, replace=True) 6py = rd.choice(10, 100, replace=True) 7xn = rd.choice(10, (100, 1, 1, 1), replace=True) 8 9print('tn =', tn) 10print('py =', py) 11 12# オリジナル 13 14def test1(): 15 for n in range(1000): 16 ansr = np.asarray([xn[rd.choice(np.where(tn == y)[0], 1, replace=True)[0]] for y in py]) 17 18# ちょっと早くしてみた版 19 20indices = [np.where(tn == y)[0] for y in range(0,10)] 21 22def test2(): 23 for n in range(1000): 24 ansr = np.asarray([xn[rd.choice(indices[y], replace=True)] for y in py]) 25 26def sw(f): 27 t1 = time.time() 28 f() 29 t2 = time.time() 30 et = t2 - t1 31 print(f"elapsed: {et}") 32 33sw(test1) 34sw(test2)

==>
elapsed: 3.420769453048706
elapsed: 0.9050662517547607


Windows 10, AMD A10-7700K APU 3.4GHz
Python 3.6.0


以上はあくまで同じことを繰り返しやらされるPythonインタープリタの身になって考えてみた小手先のチューニングに類するものだと思いますので、ループ本体のアルゴリズムを見直した方が効果が高いとは思います。

なお、forループの中でやっていることに依存するかも知れませんが、単純に複数スレッド(複数プロセス)でやってみたらどうでしょうか。自分のPCは2コアしかないですが、4コアのプロセッサーのPCを使っていた当時、計算量が大きいものを8スレッド程度でやるとちょっと感動するぐらい早く感じた経験があります。数倍高速化ってのはあなどれない性能向上と思います。

投稿2017/12/23 05:40

編集2017/12/25 02:05
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumatsuoka

2017/12/25 01:46

KSwordOfHasteさん、回答ありがとうございました。 いつも何も考えずにループを書いているので、参考になりました。 "インタプリタの身になって考えてみる"を考えて見たいと思います。 また、アルゴリズムももう1度考えてみたいと思います。 ありがとうございました。
yumatsuoka

2017/12/25 01:46

KSwordOfHasteさん、回答ありがとうございました。 いつも何も考えずにループを書いているので、参考になりました。 "インタプリタの身になって考えてみる"を考えて見たいと思います。 また、アルゴリズムももう1度考えてみたいと思います。 ありがとうございました。
mkgrei

2017/12/25 01:48

勘違いかもしれませんが[y]が必要かもしれません。 ansr = np.asarray([xn[rd.choice(indices[y], replace=True)] for y in py])
KSwordOfHaste

2017/12/25 02:00

mkgreiさんご指摘ありがとうございます。 おっしゃるとおりindices[y]としなければいけませんでした! 結果をちゃんと見ておくべきでした。申し訳ありません。 コードと測定しなおした結果を反映いたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問