- 投稿日:2019-07-19T17:20:50+09:00
PythonでベクトルをL2正規化(normalization)する方法一覧
Pythonを使ってベクトルをL2正規化(normalization)する方法が色々あるのでまとめます。
※L2正則化(regularization)= Ridgeではありません。L2正規化とは
ベクトル$x = (x_1,x_2,...,x_n)$に対応するL2正規化は以下のように定式化されます。
x_{L2\,norm} = \frac{x}{||x||_2}ここで、$||x||_2$は、以下の式で求まる$x$のL2ノルムです。
||x||_2 = \sqrt{(\sum_i x_i^2)} = \sqrt{x_1^2 + x_2^2 + ... + x_n^2}ベクトル$x$をL2正規化すると、長さが1のベクトルになります。
2次元空間で考えた場合、この操作は任意の2次元ベクトルを原点を中心とした半径1の円上へのベクトルに変換していると考えることができます。
3次元の場合は原点を中心とした半径1の球面上へのベクトルに変換します。
4次元以上はイメージが難しいですが、同じように原点を中心とする半径1の超球面上へのベクトルに変換すると考えれば良いと思います。
pythonでの計算方法
上記のようなL2正規化ですが、pythonでは色々と計算方法があるようなので以下にまとめます。
他にもあると思うので、見つけたら追記します。直接計算する
定義に従って計算すれば良いです。
# 定義に従って計算 x = np.array([1,2,3,4,5]) x_l2_norm = sum(x**2)**0.5 x_l2_normalized = x / x_l2_norm # 検算 np.linalg.norm(x_l2_normalized,ord=2) # 1.0
numpy.linalg.norm
numpy.linalg.normを使って計算することも可能です。
こいつはベクトルxのL2ノルムを返すので、L2ノルムを求めた後にxを割ってあげる必要があります。# numpy.linalg.normを使う x = np.array([1,2,3,4,5]) x_l2_norm = np.linalg.norm(x,ord=2) x_l2_normalized = x / x_l2_norm # 検算 np.linalg.norm(x_l2_normalized,ord=2) # 1.0
sklearn.preprocessing.normalizeみんな大好きscikit-learnでも計算可能です。
2次元の場合はaxisで軸の指定します。axis=0で列方向、axis=1(デフォルト)で行方向に正規化を行います。# sklearn.preprocessing.normalizeを使う from sklearn.preprocessing import normalize x = [[1,2,3,4,5],] x_l2_normalized = normalize(x,norm='l2') x_2d = [[1,2,3,4,5],[6,7,8,9,10]] x_2d_l2_normalized = normalize(x_2d,norm='l2') x_2d_l2_normalized2 = normalize(x_2d,norm='l2',axis=0) # 検算 print(np.linalg.norm(x_l2_normalized,ord=2)) print(np.linalg.norm(x_2d_l2_normalized[0,:],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[1,:],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[:,0],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[:,1],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[:,2],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[:,3],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[:,4],ord=2)) # 1.0 # 1.0 # 1.0 # 1.0 # 1.0 # 1.0 # 1.0 # 0.9999999999999999
keras.backend.l2_normalizekerasにもあります。backendはtensorflowです。
(tf.keras.backend.l2_normalizeというものもありました)# keras.backend.l2_normalizeを使う from keras import backend as K x = [1.,2.,3.,4.,5.] x_2d = [[1.,2.,3.,4.,5.],[6.,7.,8.,9.,10.]] x_l2_normalized = K.l2_normalize(x,axis=0) x_2d_l2_normalized = K.l2_normalize(x_2d,axis=0) x_2d_l2_normalized2 = K.l2_normalize(x_2d,axis=1) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) x_l2_normalized = sess.run(x_l2_normalized) x_2d_l2_normalized = sess.run(x_2d_l2_normalized) x_2d_l2_normalized2 = sess.run(x_2d_l2_normalized2) # 検算 print(np.linalg.norm(x_l2_normalized,ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,0],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,1],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,2],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,3],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,4],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[0,:],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[1,:],ord=2)) #1.0000001 #1.0 #0.99999994 #1.0 #0.99999994 #1.0 #1.0000001 #1.0
tf.math.l2_normalize※tensorflow 1.11までは
tf.nn.l2_normalizeとして提供されていたようです。import tensorflow as tf x = tf.Variable([1,2,3,4,5], dtype=tf.float32) x_2d = tf.Variable([[1,2,3,4,5],[6,7,8,9,10]], dtype=tf.float32) x_l2_normalized = tf.math.l2_normalize(x,axis=0) x_2d_l2_normalized = tf.math.l2_normalize(x_2d,axis=0) x_2d_l2_normalized2 = tf.math.l2_normalize(x_2d,axis=1) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) x_l2_normalized = sess.run(x_l2_normalized) x_2d_l2_normalized = sess.run(x_2d_l2_normalized) x_2d_l2_normalized2 = sess.run(x_2d_l2_normalized2) # 検算 print(np.linalg.norm(x_l2_normalized,ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,0],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,1],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,2],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,3],ord=2)) print(np.linalg.norm(x_2d_l2_normalized[:,4],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[0,:],ord=2)) print(np.linalg.norm(x_2d_l2_normalized2[1,:],ord=2)) #1.0000001 #1.0 #0.99999994 #1.0 #0.99999994 #1.0 #1.0000001 #1.0おわりに
いろいろありますねー。用途に合わせて使い分けていきましょー(?)
(pythonは変数のスコープどうなってんすか。。。)
- 投稿日:2019-07-19T12:00:02+09:00
cuDNN初期化エラーが出てTensorFlowGPUの学習ができなくなったけど解決した話
Jupyterでコード書いて機械学習しようとしたとき、エラー吐いてどハマりしたので共有しといた方が良いと思った話です。
環境
Anaconda+JupyterとCUDA+TensorFlowGPU+Kerasでディープラーニングさせている。CUDAは10.0、cuDNNも該当バージョンをインストール済み。CPU版はアンインストールした。ちゃんと動くはずの環境。ていうか今までちゃんと動いてた。
状況
Kerasで学習をさせようとするとエラーを吐く。1回目はちゃんと動く。でも、他のコードを実行すると止まる。場合によっては1回目でも止まる。PC再起動させると1回は治る。でも2回目はエラー。えらー。error。
昨日までちゃんと動いてたのに。何もしてないのに壊れた。具体的にはこんな感じのエラーメッセージが出て動かない。
UnknownError: 2 root error(s) found.
(0) Unknown: Failed to get convolution algorithm. This is probably because cuDNN failed to initialize, so try looking to see if a warning log message was printed above.
[[{{node conv2d_1/convolution}}]]
[[metrics/acc/Mean/_193]]調べる
エラーを読むと、cuDNNの初期化に失敗してるらしい。ググってみたらどうやらcuDNNのPATHが通ってないとこうなるよ、とのこと。
環境変数調べる。ちゃんとパス通ってるように見える。Anacondaごと再インストールしても症状が治らない。そもそも1回はちゃんと動くのが最高に意味不明でCOOL。
入れなおせど入れなおせど我が症状治らざり。ぢっとタスクマネージャを見る
Jupyter終了させているのにPythonプロセスが生きてた。しかもえらい量メモリ確保してる。この辺でなにかおかしいことに気付く。もしかしてJupyterって終了させてもメモリ解放しない?いやいやそんなまさか…
再度調べる
そのまさかだった。JupyterNotebookはタブを閉じてもプログラムは終了しないとのこと。まじか。今までタブを閉じて終わらせてた。無知って怖い。
このあたりでJupyterのこの辺の仕様が原因な気がしだしてTensorFlowのGPU確保の仕方も調べる。そしてTensorFlowの仕様
TensorFlow-GPUは、デフォルトだとGPUの空いている領域をすべて確保しようとする。すべてです。ALL。
つまり、TensorFlow-GPUを使った機械学習プログラムを複数同時に走らせると1つめは普通に通るけど2つめはGPUを確保できないので初期化に失敗する。これがcuDNN failed to initializeの正体。
そしてJupyterをタブ閉じで終わらせるとGPUを確保したままゾンビ化する。その後Jupyterを立ち上げ直してもGPUはゾンビ化したコードに専有されたままなのでこれも初期化失敗する。これが1回目でも学習失敗する症状の正体。
試しに1つめのコードを走らせたあと、Jupyter上でコードを停止させてから2つめを走らせると、普通に動いた。CUDAもcuDNNもAnacondaも悪くない。悪いのはGPUをひとり占めしようとするTensorFlowとタブを消したらゾンビ化するJupyterやったんや。結論
コードは実行が終わったらちゃんと停止させましょう。Jupyterを終了させるときはちゃんとQuiteで終わらせましょう。TensorFlowが確保するメモリ量を制限するやり方も有効です。やり方は以下の記事が分かりやすいです。おわり。
参考文献


