実現したいこと
matplotlibによるアニメーションの保存時間を短縮したい
前提
animationの保存に30分以上かかってしまいます。保存されたgifはイメージ通りで正しいと思われます。
発生している問題・エラーメッセージ
エラーメッセージ無し
保存時間が長すぎる
該当のソースコード
python
1#必要なライブラリのインポート 2import random 3import numpy as np 4import matplotlib.pyplot as plt 5import numpy.random as rand 6 7#行数と列数の指定 8m = 20 9n = 20 10#訓練データの数を指定 11n_x =4000 12 13#ランダムなRGB値をもつn_xこの訓練データを生成。各要素は3つずつ。 14train_data = np.random.randint(0, 255, (n_x, 3)) 15 16#ランダムなRGB値を持つSOMの初期状態をsomと定義。生成された整数値を浮動小数点に変換。 17som = np.random.randint(0, 255, (m, n, 3)).astype(float) 18 19#SOMを画像として表示する。浮動小数点の値をsom.astype(int)で整数に変換。軸オブジェクトを取得。x軸とy軸を非表示に設定。 20plt.imshow(som.astype(int)) 21ax = plt.gca() 22ax.axes.xaxis.set_visible(False) 23ax.axes.yaxis.set_visible(False) 24# SOM内のBMUを見つける。SOMと入力ベクトルx(ランダムに抽出された訓練データ)の間のユークリッド距離の二乗を計算し、最小値の座標を返す。 25def find_BMU(SOM,x): 26 distSq = (np.square(SOM - x)).sum(axis=2) 27 return np.unravel_index(np.argmin(distSq, axis=None), distSq.shape) 28 29# update_weightsは、与えられた1つのトレーニング例と、BMUの座標を含むモデルパラメータと共に、SOMのセルの重みを更新する 30def update_weights(SOM, train_ex, learn_rate, radius_sq, 31 BMU_coord, step=3): 32 g, h = BMU_coord 33 #半径が0に近いとき、BMUのみ変更する 34 if radius_sq < 1e-3: 35 SOM[g,h,:] += learn_rate * (train_ex - SOM[g,h,:]) 36 return SOM 37 # BMUの小さい近傍全てのセルを更新する。dist_funcは距離感数で、ガウス関数に基づいており、BMUから離れるにつれて減衰する。学習率、距離感数、トレーニング例との差を乗算して、近傍セルの重みを更新する。 38 39 for i in range(max(0, g-step), min(SOM.shape[0], g+step)): 40 for j in range(max(0, h-step), min(SOM.shape[1], h+step)): 41 dist_sq = np.square(i - g) + np.square(j - h) 42 dist_func = np.exp(-dist_sq / 2 / radius_sq) 43 SOM[i,j,:] += learn_rate * dist_func * (train_ex - SOM[i,j,:]) 44 return SOM 45 46 47def train_SOM(SOM, train_data, learn_rate = .001, radius_sq = 1, 48 lr_decay = .001, radius_decay = .1, epochs = 100): 49#初期の学習率と半径の2乗を保持する(学習率と減衰を制御するため) 50 learn_rate_0=learn_rate 51 radius_0 = radius_sq 52#指定されたエポック数の回数だけトレーニングを繰り返す。 53 for epoch in np.arange(0, epochs): 54 #各エポックごとに、トレーニングデータセットをランダムにシャッフルする。 55 rand.shuffle(train_data) 56 #SOMの重みを更新する 57 for train_ex in train_data: 58 g, h = find_BMU(SOM, train_ex) 59 SOM = update_weights(SOM, train_ex, 60 learn_rate, radius_sq, (g,h)) 61 # 学習率と半径の更新(学習率は指数関数的に減衰し、エポックごとに小さくなる。同様に、半径も指数関数的に減衰し、トレーニングの進行に応じて小さくなる) 62 learn_rate = learn_rate_0 * np.exp(-epoch * lr_decay) 63 radius_sq = radius_0 * np.exp(-epoch * radius_decay) 64 return SOM 65 66import matplotlib.animation as animation 67from PIL import Image 68 69#初期のSOMの状態を表示。somを整数型に変換し、x軸y軸を非表示にする。 70fig, ax = plt.subplots(figsize=(3, 3)) 71ax.imshow(som.astype(int)) 72ax.axes.xaxis.set_visible(False) 73ax.axes.yaxis.set_visible(False) 74 75 76def update(frame): 77 global som 78 SOM = train_SOM(som, train_data) 79 ax.imshow(SOM.astype(int)) 80 som = SOM 81 return ax 82 83ani = animation.FuncAnimation(fig, update, frames=1000, interval=.000001, blit=False) 84# アニメーションをGIFファイルとして保存する 85ani.save('SOM_training_animation.gif', writer='imagemagick', fps=10)
試したこと
学習率などパラメータの変更は試してみましたが、変化がありませんでした。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
> animationの保存に30分以上かかってしまいます。
動画の時間とSPFはいくつでしょうか?
コメントいただきありがとうございます。
動画時間は15秒ほどです。
SPFについては確認方法が分からず、すみません
「matplotlibによるアニメーションの保存時間を短縮したい」とのことですが、「学習率などパラメータの変更は試してみましたが、変化がありませんでした。」にもあるように問題はmatplotlib以外ということでしょうか?それともアニメーション作成をしない場合はプログラムは短時間で終了するのでしょうか?
最後のani.save以前のコードのみで実行すると、1秒足らずで完了する状況です。
ただ、保存の際にそれ以前のコードを繰り返し処理してしまっているようなので、matplotlibの問題ではないのかもしれません。すみません、当方初心者なもので知識が不足しています…
ani.saveをplt.show()にしたらどうなりますか?ハードディスクへの保存に時間が掛かっているかどうかの確認です。
plt.show()に変更したところ、1秒以内で結果画像が出力できました
ところで、FuncAnimationのintervalはミリ秒指定ですがコードの数値で合ってますか?
300ミリ秒程度からだんだん小さくして試していたのですが、数値をどれだけ小さくしても変化が少しも速くならず、この数値まで試したところで諦めたという状況です…
![guest](/img/icon/icnUserSample.jpg)