20190719のTensorFlowに関する記事は2件です。

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の円上へのベクトルに変換していると考えることができます。

image.png

3次元の場合は原点を中心とした半径1の球面上へのベクトルに変換します。

image.png

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_normalize

kerasにもあります。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は変数のスコープどうなってんすか。。。)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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が確保するメモリ量を制限するやり方も有効です。やり方は以下の記事が分かりやすいです。おわり。

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む