python徒手实现反向传播算法
程序员文章站
2024-01-26 10:20:22
...
1. 项目背景
假设有如上图所示的全连接神经网络,该网络共有三层L1、L2、L3,输入层为X。每层输出经过Sigmoid**函数。
其中X为100*3的矩阵,即表示有100个样本,每个样本有3个特征。L1层有5个神经元,L2层有8个神经元,L3有10个神经元。y为100*1的向量,是数据集X对应的标签。W1,W2,W3矩阵形状如图所示。
2. 导入所需的库
import numpy as np
import pandas as pd
for i in [np, pd]:
print(i.__name__,": ",i.__version__,sep="")
输出:
numpy: 1.17.4
pandas: 0.25.3
3. 导入数据
根据如上所述,X为1003的矩阵,y为1001的矩阵
df = pd.read_csv("admission.txt")
# 构造X和y
X = df[["Exam1","Exam2","Exam3"]].as_matrix()
y = df["Admitted"].as_matrix().reshape(100,1)
print(X.shape, y.shape)
输出:
(100, 3) (100, 1)
print(X[:5])
print(y[:5])
[[34.62365962 78.02469282 56.32417622]
[30.28671077 43.89499752 37.09085415]
[35.84740877 72.90219803 54.3748034 ]
[60.18259939 86.3085521 73.24557574]
[79.03273605 75.34437644 77.18855624]]
[[0]
[0]
[0]
[1]
[1]]
4. 前向传播
注意:为了方便计算与推导,省略偏置项b。对于偏置项b,在实际应用中可以在数据集第一列添加全1的方式进行处理,则在训练的模型结果参数W中第一行即是b的值。
4.1 Sigmoid函数
Sigmoid函数用f(x)表示,则f(x)及其导数如公式(1)所示:
def Sigmoid(x):
return 1/(1+np.exp(-x))
def SigmoidPrime(y):
return y*(1-y)
4.2 初始化权重W
根据上面的分析,W1是3*5的矩阵,W2是5*8的矩阵,W3是8*1的矩阵
np.random.seed(1) # 指定随机种子,方便复现
W1 = 2 * np.random.random((3,5))-1 # random函数默认返回(0,1)区间上的值
W2 = 2 * np.random.random((5,8))-1
W3 = 2 * np.random.random((8,1))-1
for i in [W1, W2, W3]:
print(i.shape)
输出:
(3, 5)
(5, 8)
(8, 1)
4.3 各层输出
- 输入层:X=X,X为100*3的矩阵
- L1层:L1=f(XW1),L1为100*5的矩阵
- L2层:L2=f(L1W2),L2为100*8的矩阵
- L3层:L3=f(L2W3),L3为100*1的矩阵
L1 = Sigmoid(np.dot(X,W1))
L2 = Sigmoid(np.dot(L1,W2))
L3 = Sigmoid(np.dot(L2,W3))
5. 反向传播
5.1 损失函数
定义模型的目标函数(即损失函数)为均方误差,即:
根据误差反向传播的思想,需要求出损失函数关于W1、W2和W3的偏导数,再根据偏层数进行W参数的更新。
5.2 求偏导
求导过程中注意:
- a. 矩阵点乘(矩阵元素对应位置相乘)和矩阵乘法的区别(上式中绿色标部分)。
- b. 注意矩阵求导法则(上式中红色标注部分):
为了简化上式的书写及方便python编程,令:
则根据(5)式,(3)式中的偏导数可表示为:
5.3 反向传播过程
error = L3 - y
delta3 = error * SigmoidPrime(L3)
delta2 = delta3.dot(W3.T)*SigmoidPrime(L2)
delta1 = delta2.dot(W2.T)*SigmoidPrime(L1)
W3 -= alpha * np.dot(L2.T, delta3)
W2 -= alpha * np.dot(L1.T, delta2)
W1 -= alpha * np.dot(X.T, delta1)
6. 完整代码训练
import numpy as np
import pandas as pd
iterations = 500000 # 设置迭代次数
alpha = 0.1 # 设置学习率
def Sigmoid(x):
return 1/(1+np.exp(-x))
def SigmoidPrime(y):
return y*(1-y)
df = pd.read_csv("admission.txt")
# 构造X和y
X = df[["Exam1","Exam2","Exam3"]].as_matrix()
y = df["Admitted"].as_matrix().reshape(100,1)
W1 = 2 * np.random.random((3,5))-1 # random函数默认返回(0,1)区间上的值
W2 = 2 * np.random.random((5,8))-1
W3 = 2 * np.random.random((8,1))-1
for i in range(iterations):
L1 = Sigmoid(np.dot(X,W1))
L2 = Sigmoid(np.dot(L1,W2))
L3 = Sigmoid(np.dot(L2,W3))
error = L3 - y
delta3 = error * SigmoidPrime(L3)
delta2 = delta3.dot(W3.T)*SigmoidPrime(L2)
delta1 = delta2.dot(W2.T)*SigmoidPrime(L1)
W3 -= alpha * np.dot(L2.T, delta3)
W2 -= alpha * np.dot(L1.T, delta2)
W1 -= alpha * np.dot(X.T, delta1)
if i%10000 == 0:
print("Error:",np.mean(np.abs(error)))
输出:
Error: 0.4744584876195863
Error: 0.47999999998146775
Error: 0.47999999998126625
Error: 0.47999999998106035
Error: 0.47999999998084986
Error: 0.4799999999806344
Error: 0.4799999999804141
Error: 0.47999999998018855
Error: 0.479999999979958
Error: 0.4799999999797217
Error: 0.47999999997947973
Error: 0.479999999979232
Error: 0.4799999999789782
Error: 0.47999999997871784
Error: 0.479999999978451
Error: 0.4799999999781772
Error: 0.4799999999778965
Error: 0.4799999999776082
Error: 0.4799999999773125
Error: 0.4799999999770086
Error: 0.4799999999766964
Error: 0.47999999997637555
Error: 0.47999999997604553
Error: 0.4799999999757064
下一篇: 全局变量,本地变量与静态本地变量