numpy、tensorflow、keras、pytorch の 4 つのフレームワークはそれぞれロジスティック回帰分類アルゴリズムを実装し、勾配計算とパラメータ更新を実現します。

ロジスティック回帰

予備知識

ロジスティック回帰は主に二項分類問題で使用され、次の式が使用されます: 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 ( 1p )

損失関数については、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 ) _ _( 1y ) 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はい+1p1はい

導入事​​例

ここでは、入力が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はい+1p1はい)p ( 1p )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はい+1p1はい)p ( 1p )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 を除いて、他のフレームワークは内部的に勾配リターンとパラメーター更新を実装しているため、モデルのトレーニングがはるかに便利です。また、これらのフレームワークは一般的に使用される損失関数と評価関数も実装していますが、面接中に面接官が質問を許可する場合があります。マニュアル コード 完全なモデル トレーニング プロセスでは、各ステップを十分に理解する必要があります。

話は安いです、コードを見せてください

おすすめ

転載: blog.csdn.net/baoxin1100/article/details/108830671