<目次>
Pythonで多クラスのロジスティック回帰を実装した例をご紹介
実装のフロー
STEP1:モデルの定義
STEP2:誤差関数の定義
STEP3:最適化手法の定義(例:勾配降下法)
STEP4:セッションの初期化
STEP5:学習
サンプルプログラム
Pythonで多クラスのロジスティック回帰を実装した例をご紹介
多クラス分類のロジスティック回帰について、Pythonで実装したサンプルプログラムをご紹介します。
実装のフロー
STEP1:モデルの定義
STEP2:誤差関数の定義
STEP3:最適化手法の定義(例:勾配降下法)
STEP4:セッションの初期化
STEP5:学習
・ループ変数の範囲で処理を繰り返す。
サンプルプログラム
(サンプルプログラム)
import numpy as np
import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
from sklearn.utils import shuffle
import matplotlib.pyplot as plt
# 入力xの次元
M = 2
# 出力yの次元(クラス数)
K = 3
# 入力データセットの総
nc = 10
# 入力データセットの総数
N = nc * K
def mc_logistic_regression(X_arg,t_arg):
############################################
# STEP1:モデルの定義
############################################
# 入力の電気信号Xの初期化
X = tf.constant(X_arg, dtype = tf.float64, shape=[N,M])
xn = tf.Variable(tf.zeros([M,1],tf.float64),dtype = tf.float64, shape=[M,1])
# 重みWの定義
Weight = tf.Variable(tf.zeros([K,M],tf.float64), dtype = tf.float64, shape=[K,M])
# バイアスbの定義 (※データはn個でも1つのbを更新)
bias = tf.Variable(tf.zeros([K,1],tf.float64), dtype = tf.float64, shape=[K,1])
# ソフトマックス関数:y = softmax(Wx + b)の定義 (※データはn個でも1つのyを更新)
y = tf.Variable(tf.zeros([K,1],tf.float64), dtype = tf.float64, shape=[K,1])
# 正解値tの定義
t = tf.Variable(t_arg, dtype = tf.float64, shape=[N,K])
# 重みWの勾配(∂E(W,b)/∂W)の定義
dWeight = tf.Variable(tf.zeros([K,M],tf.float64), dtype = tf.float64, shape=[K,M])
# バイアスbの勾配(∂E(W,b)/∂b)の定義
dbias = tf.Variable(tf.zeros([K,1],tf.float64), dtype = tf.float64, shape=[K,1])
# 学習率ηの定義
eta = 0.1
# Epoc数の定義
epocs = 1000
############################################
# STEP4:セッションの初期化
############################################
# ⇒今回は不要
# (TensorFlow v2以降はSessionを使用しないため)
############################################
# STEP5:学習
############################################
for epoc in range(epocs):
# バッチのデータ数だけ繰り返し
for n in range(N):
# データをシャッフル
X_,t_ = shuffle(X.numpy(),t.numpy())
#X_,t_ = X.numpy(),t.numpy()
# 取り出したX_[n]を転置してxnに格納(Mx1)
xn.assign(tf.transpose([X_[n]]))
############################################
# STEP2:誤差関数の定義
############################################
# ⇒今回は不要
# (確率的勾配降下法を使うため、誤差関数Eは計算不要)
############################################
# STEP3:最適化手法の定義(例:勾配降下法)
############################################
# ソフトマックス関数:y = softmax(Wx + b)の計算
# y[K,1] = softmax( Weight[K×M] × X[M×1] + bias[K×1] )
# reshapeに関しては、softmax関数の引数が[K]の形式でないと適切に動かない為に使用している。
# reshapeで[K]に変換してsoftmaxしたのち、再度[K,1]に戻して行列計算できる形に戻す。
y.assign( tf.reshape( tf.nn.softmax(tf.reshape(tf.matmul(Weight,xn)+bias,[K])),[K,1]).numpy() )
# 重みwの勾配(∂E(W,b)/∂W)の計算
# dWeight[K,M] += ( tn[K×1](転置) - y[K×1] ) × xn[1×M](転置)
dWeight.assign(tf.matmul((tf.transpose([t_[n]])-y),tf.transpose(xn)).numpy())
# バイアスbの勾配(∂E(w,b)/∂b)の計算
dbias.assign( tf.transpose([t_[n]])-y)
# コンソール出力
decimals = 4
print("Epoc= ", epoc+1,
"No. = ", n,
"\r\n\t x1,x2 \t\t=", np.array_repr(np.round(X[n].numpy(),decimals)),
"\r\n\t t \t\t=", np.array_repr(np.round(t[n].numpy(),decimals)),
"\r\n\t w1,w2 \t\t=", np.array_repr(np.round(Weight.numpy(),decimals)).replace('\n', '').replace(' ', ''),
"\r\n\t b \t\t=", np.array_repr(np.round(bias.numpy(),decimals)).replace('\n', '').replace(' ', ''),
"\r\n\t y \t\t=", np.array_repr(np.round(y.numpy(),decimals)).replace('\n', '').replace(' ', ''),
"\r\n\t dw1,dw2 \t=", np.array_repr(np.round(dWeight.numpy(),decimals)).replace('\n', '').replace(' ', ''),
"\r\n\t db \t\t=", np.array_repr(np.round(dbias.numpy(),decimals)).replace('\n', '').replace(' ', ''),
)
# 重みwの再計算
Weight.assign_add( tf.math.scalar_mul(eta,dWeight) )
# バイアスbの再計算
bias.assign_add( tf.math.scalar_mul(eta,dbias) )
# グラフ生成準備
plot_line(M,K,Weight,bias)
plot_dot(X,"r")
def plot_dot(data,type):
# 点の描画
x, y = [x1 for x1,y1 in data],[y1 for x1,y1 in data]
plt.scatter(x,y, color = 'b', edgecolors='k')
# plot_line:グラフ描画関数(入力M=2にのみ対応)
def plot_line(M,K,W,b):
# K=2以上の場合
if K > 1:
# クラスy1とy2の境界線
# w11*x1 + w12*x2 + b1 = w21*x1 + w22*x2 + b2
# ⇒ x2 = -{(w11 - w21)/(w12 - w22)}*x1 - (b1 - b2)/(w12 - w22)
# クラスy2とy3の境界線
# w21*x1 + w22*x2 + b2 = w31*x1 + w32*x2 + b3
# ⇒ x2 = -{(w21 - w31)/(w22 - w32)}*x1 - (b2 - b3)/(w22 - w32)
for k in range(0,K-1):
x,y = [],[]
for x1 in range(100):
x1_ = x1/10
denom = (W[k][1]-W[k+1][1])
x2 = -((W[k][0]-W[k+1][0])/denom)*x1_ - (b[k][0]-b[k+1][0])/denom
x.append(x1_)
y.append(x2)
plt.plot(x,y)
def main():
# 初期値を設定し学習実行
# テスト用データセット
# np.random.seed(0)
X1 = np.random.randn(nc,M) + np.array([0,10])
X2 = np.random.randn(nc,M) + np.array([5,5])
X3 = np.random.randn(nc,M) + np.array([10,0])
t1 = np.array([[1,0,0] for i in range(nc)])
t2 = np.array([[0,1,0] for i in range(nc)])
t3 = np.array([[0,0,1] for i in range(nc)])
X = np.concatenate((X1,X2,X3), axis=0)
t = np.concatenate((t1,t2,t3), axis=0)
mc_logistic_regression(X,t)
# x軸の命名
plt.xlabel('x 軸',fontname="Meiryo")
# y軸の命名
plt.ylabel('y 軸',fontname="Meiryo")
# タイトル
plt.title('多クラスロジスティック回帰',fontname="Meiryo")
# 描画関数
plt.show()
if __name__ == "__main__":
main()
(図131)
(例)出力結果
Epoc= 1 No. = 0
x1,x2 = array([0.6383, 9.0615])
t = array([1., 0., 0.])
w1,w2 = array([[0.,0.],[0.,0.],[0.,0.]])
b = array([[0.],[0.],[0.]])
y = array([[0.3333],[0.3333],[0.3333]])
dw1,dw2 = array([[-1.471,-2.1043],[2.9419,4.2086],[-1.471,-2.1043]])
db = array([[-0.3333],[0.6667],[-0.3333]])
~中略~
Epoc= 30 No. = 29
x1,x2 = array([10.632, -0.321])
t = array([0., 0., 1.])
w1,w2 = array([[-1.9226,1.3133],[0.5322,0.5343],[1.3903,-1.8476]])
b = array([[-0.068],[0.14],[-0.072]])
y = array([[0.9891],[0.0109],[0.]])
dw1,dw2 = array([[0.0159,0.1162],[-0.0159,-0.1162],[-0.,-0.]])
db = array([[0.0109],[-0.0109],[-0.]])