数据来源: https://blog.csdn.net/u013733326/article/details/79702148
参考:https://blog.csdn.net/qq_29762941/article/details/80343185
手动建立一个基于反向传播的神经网络,包含一个隐藏层,实现一个二维平面数据分类。可以在jupyter notebook上分步进行或在pycharm上建立项目运行。
import numpy as np #引入标准库
import matplotlib.pyplot as plt
np.random.seed(1) #生成随机种子,保证验证结果一样
(1)创建数据集
#创建二维分类数据集 ,直接调用,得到训练数据
def load_planar_dataset():
np.random.seed(1)
m = 400 # number of examples
N = int(m/2) # number of points per class
D = 2 # dimensionality
X = np.zeros((m,D)) # data matrix where each row is a single example
Y = np.zeros((m,1), dtype='uint8') # labels vector (0 for red, 1 for blue)
a = 4 # maximum ray of the flower
for j in range(2):
ix = range(N*j,N*(j+1))
t = np.linspace(j*3.12,(j+1)*3.12,N) + np.random.randn(N)*0.2 # theta
r = a*np.sin(4*t) + np.random.randn(N)*0.2 # radius
X[ix] = np.c_[r*np.sin(t), r*np.cos(t)]
Y[ix] = j
X = X.T
Y = Y.T
return X, Y
(2)测试:
X, Y = load_planar_dataset()
print (X.shape, Y.shape)
得到输入数据的结构
(2, 400) (1, 400)
(3)绘制图形:
plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral) #绘制散点图
(2,400)的训练数据X, 每一列代表一个点的坐标,总共400个点。
(1,400)1行400列的为监督数据,即标定有400个。
①初始化神经网络结构:激活函数确定;确定输入层,隐藏层,输出层;
def sigmoid (Z)
def layer_sizes(X, Y)
②初始化网络参数数值:传递权重w,偏置量b;
def initlalize_parameters(n_x, n_h, n_y)
③神经网络前向传播:前向传播计算;成本函数计算;
def forward_propagation(X, parameters)
def compute_cost(A2,Y,parameters):
④神经网络反向传播:反向传播梯度计算;反向传播参数更新;
def backward_propagation(parameters, cache, X, Y)
def uppdata_parameters(parameters,grads,learning_rate=1.2)
1.激活函数:激活函数是神经网络脱离线性(wX+b结构属于线性变换)进行空间扭曲的关键部分,可以选常用的sigmoid函数与双曲正切函数tanh,这里我们选sigmoid,读者可以根据自己的喜好进行尝试。
def sigmoid (Z) :
return 1/(1+np.exp(-Z))
2.网络结构层数初始化:
输入数据是(2,400), 两行分别是坐标 (xi,yi),若以输入参数2个,即两个神经元做为输入;
每个输入对应输出数据为1个标定类别:红或蓝,即一个神经元做为输出;
隐藏层我们设计4个神经元进行训练;
def layer_sizes(X, Y):
n_x = X.shape[0]
n_h = 4
n_y = Y.shape[0]
return (n_x, n_h, n_y)
#该函数返回各个层级的神经元数量,根据神经元数量来确定矩阵维度
按照上述计算,神经网络的结构为(2-4-1),为了方便计算,采用矩阵形式进行传播计算即:wx+b = y
根据矩阵相乘的维度限制确定w 与 b 矩阵的维度,方法如下:
w[4, _ ] * x[2, 1] + b[ _, _] = y1;
根据神经元数量可以完成上式,根据乘法规则,填充如下:
w[4, 2 ] * x[2, 1] + b[ 4, 1] = y1;
1.初始化参数矩阵
def initlalize_parameters(n_x, n_h, n_y):
np.random.seed(2)
W1 = np.random.rand(n_h, n_x) * 0.01
b1 = np.zeros(shape=(n_h, 1))
W2 = np.random.rand(n_y, n_h) * 0.01
b2 = np.zeros(shape=(n_y, 1))
#创建一个字典类型的变量parameter来存储产生的矩阵
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
1.前向传播计算
对于两层的神经网络结构我们定义
Z1 = w1x + b1;
A1 = ranh(Z1);
Z2 = w2A1 + b2;
A2 = sigmoid(Z2);
def forward_propagation(X, parameters):
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
Z1 = np.dot(W1, X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2, A1) + b2
A2 = sigmoid(Z2)
#字典类型cache 存储前向计算中得到的结果
cache = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}
return (A2, cache)
2.成本函数计算
对于二分类问题,最常用的情况是以0.5为阈值进行判断,所以损失函数与逻辑回归一致。
def compute_cost(A2,Y,parameters):
m = Y.shape[1]
W1 = parameters["W1"]
W2 = parameters["W2"]
# 计算成本
logprobs = np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2))
cost = -np.sum(logprobs) / m
cost = float(np.squeeze(cost))
assert (isinstance(cost, float))
return cost
1反向梯度计算:
神经网络反向推导的过程一直搞得不是很清楚,现在写下参考大佬们的一些推导理解,供自己记录与参考。
1)目标函数
…经典代价函数
…整体代价函数,在后面补充的为权重衰减项,为的是让模型不要变的复杂,权值尽量小,简单,提升泛化能力。
有了上述的代价函数,我们选择以梯度下降的方法优化整体代价函数,找到全局最优(理想)的W,b参数。
2)反向传播更新:
根据最优化的梯度下降算法,定义一个学习率,变量在负梯度方向上进行更新,公式如下:
核心问题转化为代价函数对W,b求导:
根据求导公式,将导数计算转移成两个导数的间接计算。
引入残差变量δ,计算过程如下:
3)对于l = n-1,n-2…层的残差计算,可以根据之前的残差推断出来
推导得出前一层的残差可有当前残差与前一层参数共同确定。
4)根据上述已知公式,我们进行推导,整体梯度结果为:
其中:
所以:
def backward_propagation(parameters, cache, X, Y):
m = X.shape[1]
W1 = parameters["W1"]
W2 = parameters["W2"]
A1 = cache["A1"]
A2 = cache["A2"]
# 偏差
dZ2 = A2 - Y #用做差代替残差
dW2 = (1 / m) * np.dot(dZ2, A1.T) #矩阵相乘就是对求和的化简
db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True) #db为残差求和
#这里激活函数如果是sigmoid,应该是用a(x)(1-a(x)) 做为激励函数倒数
dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
#tanh' = 1-tanh^2
dW1 = (1 / m) * np.dot(dZ1, X.T)
db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)
grads = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}
return grads
2.参数更新
def uppdata_parameters(parameters,grads,learning_rate=1.2):
W1,W2 = parameters["W1"],parameters["W2"]
b1,b2 = parameters["b1"],parameters["b2"]
dW1,dW2 = grads["dW1"],grads["dW2"]
db1,db2 = grads["db1"],grads["db2"]
W1 = W1 - learning_rate * dW1
b1 = b1 - learning_rate * db1
W2 = W2 - learning_rate * dW2
b2 = b2 - learning_rate * db2
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
整合部分未完持续