ロジスティック回帰
予備知識
ロジスティック回帰は主に二項分類問題で使用され、次の式が使用されます: p = sigmoid ( z ) = 1 1 + e − zp = sigmoid(z) = \frac{1}{1+e^{-z}}p=sigmoid ( z ) _ _ _ _ _ _=1+e−z _1勾配の戻り公式は次のとおりです: ∂ p ∂ z = p ( 1 − p ) \frac{\partial p}{\partial z}=p(1-p)∂z _∂p _=p ( 1−p )
損失関数については、y がラベル、p が予測確率であると仮定して、バイナリ クロス エントロピー (BCE、binary_cross_entropy) を使用します。 loss = − ylog ( p ) − ( 1 − y ) log ( 1 − p ) loss = - ylog(p) -(1-y)log(1-p)ロス_ _ _=− y log ( p ) _ _−( 1−y ) log ( 1 _ _−p )勾配リターンの式は次のとおりです。
∂ loss ∂ p = − yp + 1 − y 1 − p \frac{\partial loss}{\partial p} = -\frac{y}{p}+\frac{1- y{1-p}∂p _∂ロス_ _ _=−pはい+1−p1−はい
導入事例
ここでは、入力がxxであると仮定して、2 つの隠れ層とバイアス項目を持たない分類器を実装します。x、ラベルyyy、完全に接続された 2 つの層の重みはw 1 w_1w1和 w 2 w_2 w2の場合、出力は次の式で表すことができます:
h 1 = w 1 xh 2 = w 2 h 1 p = sigmoid ( h 2 ) h_1 = w_1x \\ h_2 = w_2h_1 \\ p = sigmoid(h_2)h1=w1バツh2=w2h1p=s i g mo i d ( h _2)確率pppとラベルyyyの損失: loss = BCE ( p , y ) loss = BCE(p, y)ロス_ _ _=B C E ( p ,y )
チェーン勾配更新式を適用してw 1 w_1w1和 w 2 w_2 w2の勾配:
∂ loss ∂ w 2 = ∂ loss ∂ p ∂ p ∂ h 2 ∂ h 2 ∂ w 2 = ( − yp + 1 − y 1 − p ) ∗ p ( 1 − p ) ∗ h 1 \frac{\部分損失}{\partial w_2} = \frac{\partial loss}{\partial p}\frac{\partial p}{\partial h_2}\frac{\partial h_2}{\partial w_2}=(-\frac {y}{p}+\frac{1-y}{1-p})*p(1-p)*h_1∂w _2∂ロス_ _ _=∂p _∂ロス_ _ _∂h _2∂p _∂w _2∂h _2=( −pはい+1−p1−はい)∗p ( 1−p )∗h1 ∂ 損失 ∂ w 1 = ∂ 損失 ∂ p ∂ p ∂ h 2 ∂ h 2 ∂ h 1 ∂ h 1 ∂ w 1 = ( − yp + 1 − y 1 − p ) ∗ p ( 1 − p ) ∗ w 2 ∗ x \frac{\partial loss}{\partial w_1} = \frac{\partial loss}{\partial p}\frac{\partial p}{\partial h_2}\frac{\partial h_2}{\partial h_1} \frac{\partial h_1}{\partial w_1}=(-\frac{y}{p}+\frac{1-y}{1-p})*p(1-p)*w_2*x∂w _1∂ロス_ _ _=∂p _∂ロス_ _ _∂h _2∂p _∂h _1∂h _2∂w _1∂h _1=( −pはい+1−p1−はい)∗p ( 1−p )∗w2∗バツ
1. numpy の実装
import numpy as np
# 定义训练数据,一共1000个向量,每个向量5维,表示5个特征。
x = np.random.randn(1000, 5) # (batch_size, in_channel)
# 定义标签,如果5个特征值的和为正数,标签为1,否则标签为0。
y = (np.sum(x, axis=-1, keepdims=True)>0).astype(np.float32)
w1 = np.random.rand(5, 8) # (in_channel, hidden_channel)
w2 = np.random.rand(8, 1) # (hidden_channel, out_channel)
def sigmoid(z):
return 1/(1+np.exp(-z))
lr = 0.001 # learning rate
for i in range(10):
h1 = x.dot(w1)
h2 = h1.dot(w2)
p = np.clip(sigmoid(h2), 0.0001, 0.9999) # clip防止交叉熵出现nan
# 损失计算 BCEloss
loss = np.mean(-(y*np.log(p)+(1-y)*np.log(1-p)))
# 计算 accuracy
acc = np.mean((p>0.5)==y)
print("{}--loss:{:.4f} acc:{:.4f}".format(i, loss, acc))
# 梯度回传,计算每一个中间变量的梯度
grad_p = -y/p+(1-y)/(1-p) # dloss/dp
grad_h2 = grad_p*p*(1-p) # dloss/dp * dp/dh2
grad_w2 = h1.T.dot(grad_h2) # dloss/dp * dp/dh2 * dh2/dw2
grad_h1 = grad_h2.dot(w2.T) # dloss/dp * dp/dh2 * dh2/dh1
grad_w1 = X.T.dot(grad_h1) # dloss/dp * dp/dh2 * dh2/dh1 * dh1/dw1
# 参数更新
w1 -= lr*grad_w1
w2 -= lr*grad_w2
出力は次のとおりです。
0--損失:0.1126 acc:0.9670 1--損失:0.1020 acc:0.9580 2--損失:0.1552 acc:0.9240 3--損失:0.2582 acc:0.9070 4--損失:0.2042 acc:0.9140 5--損失: 0.0925 acc:0.9710 6--loss:0.0522 acc :0.9910 7--loss:0.0432 acc:0.9940 8--loss:0.0384 acc:0.9930 9--loss:0.0351 acc:0.9950
numpy を使用して、行列の乗算によって確率pp を手動で実装しました。pと損失 lossの計算l o s s各中間変数の勾配計算。勾配を計算するときは、各変数の勾配の形状が変数自体の形状と同じになるよう。勾配公式と連鎖ルールを知っていれば、それでも非常に簡単です。
2. テンソルフローの実装
import numpy as np
import tensorflow as tf
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
X = np.random.randn(1000, 5)
Y = (np.sum(X,axis=-1, keepdims=True)>0).astype(np.float32)
# 定义包含两个全连接层且最后一层用sigmoid激活的model
model = tf.keras.models.Sequential(
[tf.keras.layers.Dense(8, use_bias=False),
tf.keras.layers.Dense(1, use_bias=False, activation='sigmoid')]
)
x = tf.placeholder(dtype=tf.float32, shape=[None, 5]) #定义输入placeholder
y = tf.placeholder(dtype=tf.float32, shape=[None, 1]) #定义标签placeholder
p = model(x) # inference 拿到预测概率 p
# 计算BCEloss
p = tf.clip_by_value(p,1e-7,1-1e-7)
loss_fn = tf.reduce_mean(-(y*tf.log(p)+(1-y)*tf.log(1-p)))
# 计算accuracy
binary_p = tf.where(p>0.5, tf.ones_like(p), tf.zeros_like(p))
acc = tf.reduce_mean(tf.cast(tf.equal(binary_p, y), tf.float32))
# 定义Adam优化器
optimizer = tf.train.AdamOptimizer(0.1).minimize(loss_fn)
# 在sess里面训练模型
with tf.Session() as sess:
tf.global_variables_initializer().run()
for i in range(10):
loss, accuracy, _ = sess.run([loss_fn, acc, optimizer],
feed_dict={
x: X, y:Y})
print("{}--loss:{:.4f} acc:{:.4f}".format(i, loss, accuracy))
出力は次のとおりです。
0--損失:0.5949 acc:0.6660 1--損失:0.3835 acc:0.8600 2--損失:0.2731 acc:0.9260 3--損失:0.2061 acc:0.9540 4--損失:0.1606 acc:0.9710 5--損失: 0.1279 acc:0.9810 6--loss:0.1046 acc :0.9880 7--loss:0.0888 acc:0.9910 8--loss:0.0782 acc:0.9910 9--loss:0.0701 acc:0.9900
ご覧のとおり、tensorflow の実装は非常に面倒です。。これが従うプロセスは次のとおりです: 入力テンソル定義→ \rightarrow→モデル定義→ \rightarrow→推論により出力テンソルを取得→ \rightarrow→損失の定義→ \rightarrow→メトリクスの定義→ \rightarrow→オプティマイザーの定義。完全なグラフが形成され、セッションが開かれます。このセッションでは、オプティマイザーを実行してモデルをトレーニングでき、損失とメトリクスも取得できます。
3. ケラスの実装
import numpy as np
import keras
x = np.random.randn(1000, 5)
y = (np.sum(x,axis=-1, keepdims=True)>0).astype(np.float32)
model = keras.models.Sequential(
[keras.layers.Dense(8, use_bias=False),
keras.layers.Dense(1, use_bias=False, activation='sigmoid')]
)
# 模型编译
model.compile(keras.optimizers.Adam(0.001), # 使用adam优化器
loss=keras.losses.binary_crossentropy, #使用自带的BCEloss
metrics=['accuracy']) # 使用自带的accuracy
model.fit(x,y, batch_size=16, epochs=10) # 开始训练
出力は次のとおりです。
エポック 1/10 1000/1000 [=============================] - 1 秒 1ms/ステップ - 損失: 0.7465 - acc : 0.5730 エポック 2/10 1000/1000 [===============================] - 0s 140us/ステップ - 損失: 0.5893 - acc: 0.6840 エポック 3/10 1000/1000 [==============================] - 0s 148us/ステップ - 損失: 0.4777 - acc: 0.7640 エポック 4/10 1000/1000 [=============================] - 0s 139us/ステップ- 損失: 0.3973 - acc: 0.8240 エポック 5/10 1000/1000 [==============================] - 0s 137us /ステップ - 損失: 0.3374 - acc: 0.8770 エポック 6/10 1000/1000 [=============================] - 0s 140us/ステップ - 損失: 0.2929 - acc: 0.9140 エポック 7/10 1000/1000 [==============================] - 0s 134us /ステップ - 損失: 0.2586 - acc: 0.9440 エポック 8 /10 1000/1000 [==============================] - 0s 135us/ステップ - 損失: 0.2315 - acc: 0.9580 エポック 9/10 1000/1000 [==============================] - 0s 139us/ステップ - 損失: 0.2100 - acc : 0.9680 エポック 10/10 1000/1000 [==============================] - 0s 134us/ステップ - 損失: 0.1924 - acc: 0.9780
keras が非常に簡潔であることがわかります。その理由は、keras が一般的に使用される損失計算、勾配リターン、パラメーター更新用に非常に深いパッケージを作成しているためです。fit 関数を呼び出すことでモデルを簡単にトレーニングできます。ただし、numpy、torch、tensorflow の実装により、一部のモデル トレーニングの詳細にさらに注意を払うことができます。
4. pytorchの実装
import torch
x = torch.randn(1000, 5)
y = (torch.sum(x, dim=1, keepdim=True)>0).float()
# 定义一个Sequential模型
model = torch.nn.Sequential(
torch.nn.Linear(5, 8, bias=False),
torch.nn.Linear(8, 1, bias=False),
torch.nn.Sigmoid()
)
criterion = torch.nn.BCELoss() # 定义loss
optimizer = torch.optim.Adam(model.parameters(), lr=0.1) # 定义优化器
for i in range(10):
p = model(x) # inference拿到概率p
loss = criterion(p, y) # 计算loss
acc = torch.mean(((p>0.5)==y).float()) # 计算accuracy
print("{}--loss:{:.4f} acc:{:.4f}".format(i, loss, acc))
optimizer.zero_grad() # 清零梯度
loss.backward() # 梯度回传,类似于numpy中我们把每个变量的梯度都计算出来
optimizer.step() # 参数更新,类似于numpy中我们更新w1和w2的操作
0--損失:0.6549 acc:0.6260 1--損失:0.4986 acc:0.8080 2--損失:0.3646 acc:0.8780 3--損失:0.2605 acc:0.9350 4--損失:0.1877 acc:0.9620 5--損失: 0.1393 acc:0.9720 6--loss:0.1077 acc :0.9790 7--loss:0.0864 acc:0.9860 8--loss:0.0711 acc:0.9890 9--loss:0.0599 acc:0.9950
pytorch の実装もシンプルで分かりやすく、tensorflow のグラフ機構と比べると numpy に近い動作で受け入れやすいです。keras の深いカプセル化と比較すると、モデルトレーニングにおける torch の勾配計算とパラメーター更新のステップをより簡単に制御できるため、私は依然として pytorch を好みます。
要約する
numpy を除いて、他のフレームワークは内部的に勾配リターンとパラメーター更新を実装しているため、モデルのトレーニングがはるかに便利です。また、これらのフレームワークは一般的に使用される損失関数と評価関数も実装していますが、面接中に面接官が質問を許可する場合があります。マニュアル コード 完全なモデル トレーニング プロセスでは、各ステップを十分に理解する必要があります。
話は安いです、コードを見せてください