LoginSignup
29
16

More than 3 years have passed since last update.

PythonでベクトルをL2正規化(normalization)する方法一覧

Posted at

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

29
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
16