一、基本结构
一个简单的两层神经网络的基本结构分为三层:输入层(一般不考虑在内,是数据的样本特征)、隐藏层(包含3个神经元,神经元用⚪表示,神经元是一个非线性单元)、输出层(包含一个神经元,也用⚪表示)。
每个神经元的数学运算一般由两部分组成:线性部分和非线性部分,计算公式如下:
{
z
=
w
1
x
1
+
w
2
x
2
+
b
a
=
g
(
z
)
\{{z=w_1x_1+w_2x_2+b \atop a=g(z)}
{a=g(z)z=w1x1+w2x2+b
其中,
z
=
w
1
x
1
+
w
2
x
2
+
b
z=w_1x_1+w_2x_2+b
z=w1x1+w2x2+b表示线性运算,
a
=
g
(
z
)
a=g(z)
a=g(z)表示非线性运算,又称激活函数。
二、前向传播
-
神经网络前向传播过程,即神经网络从输入层到输出层的计算过程(仍以上例为例,上标表示当前神经网络层数,下标表示当前层的第几个神经单元):
从输入层到隐藏层:
{ z 1 [ 1 ] = w 1 [ 1 ] x + b 1 [ 1 ] , a 1 [ 1 ] = g ( z 1 [ 1 ] ) z 2 [ 1 ] = w 2 [ 1 ] x + b 2 [ 1 ] , a 2 [ 1 ] = g ( z 2 [ 1 ] ) z 3 [ 1 ] = w 3 [ 1 ] x + b 3 [ 1 ] , a 3 [ 1 ] = g ( z 3 [ 1 ] ) \{{z^{[1]}_1=w^{[1]}_1x+b^{[1]}_1,a^{[1]}_1=g(z^{[1]}_1) \atop {{z^{[1]}_2=w^{[1]}_2x+b^{[1]}_2,a^{[1]}_2=g(z^{[1]}_2)} \atop {z^{[1]}_3=w^{[1]}_3x+b^{[1]}_3,a^{[1]}_3=g(z^{[1]}_3)}}} {z3[1]=w3[1]x+b3[1],a3[1]=g(z3[1])z2[1]=w2[1]x+b2[1],a2[1]=g(z2[1])z1[1]=w1[1]x+b1[1],a1[1]=g(z1[1])
从隐藏层到输出层:
z [ 2 ] = w 1 [ 2 ] a [ 1 ] + b 1 [ 2 ] , a [ 2 ] = g ( z [ 2 ] ) z^{[2]}=w^{[2]}_1a^{[1]}+b^{[2]}_1,a^{[2]}=g(z^{[2]}) z[2]=w1[2]a[1]+b1[2],a[2]=g(z[2]) -
上式改为针对m个样本的情况,可以写成矩阵运算形式:
从输入层到隐藏层:
{ Z [ 1 ] = W [ 1 ] X + b [ 1 ] A [ 1 ] = g ( Z [ 1 ] ) \{{Z^{[1]}=W^{[1]}X+b^{[1]} \atop A^{[1]}=g(Z^{[1]})} {A[1]=g(Z[1])Z[1]=W[1]X+b[1]
从隐藏层到输出层:
{ Z [ 2 ] = W [ 2 ] X [ 1 ] + b [ 2 ] A [ 2 ] = g ( Z [ 2 ] ) \{{Z^{[2]}=W^{[2]}X^{[1]}+b^{[2]} \atop A^{[2]}=g(Z^{[2]})} {A[2]=g(Z[2])Z[2]=W[2]X[1]+b[2]
三、激活函数
非线性运算在神经元中一般由激活函数来实现,激活函数同一表示成g(z),以下是几个常见的激活函数:
-
Sigmoid函数:如果神经元采用Sigmoid函数作为激活函数,那么单个神经元实现的功能就相当于逻辑回归。缺点:当|z|很大时,激活函数的梯度很小,因此在这个区域内梯度下降算法会运行的较慢,应尽量避免|z|落在这个区域,应尽可能将|z|限定在0附近,从而提高梯度下降算法的运算速度。
a = 1 1 + e − z a=\frac{1}{1+e^{-z}} a=1+e−z1 -
tanh函数:是双曲正切函数。缺点同Sigmoid函数。
a = e z − e − z e z + e − z a=\frac{e^z-e^{-z}}{e^z+e^{-z}} a=ez+e−zez−e−z
-
ReLU函数:修正线性单元,是分段函数。最大的特点就是在z>0时梯度恒为1,保证了网络训练时梯度下降的速度,但是缺点是在z<=0时,梯度为0,此时神经元不工作(实际应用中证明,这种情况影响并不大)。
a = m a x ( 0 , z ) a=max(0,z) a=max(0,z)
-
Leaky ReLU函数:是ReLU函数的改进,两者区别仅在于当z<=0时,a不恒为0,而是有一个较小的梯度(大小不唯一),这样做的好处时始终保持梯度不为0。
a = m a x ( 0.01 z , z ) a=max(0.01z,z) a=max(0.01z,z)
-
选择合适的激活函数的方法:
- 对于隐藏层的激活函数:一般来说tanh函数好于Sigmoid函数,因为tanh函数取值范围在[-1,+1],隐藏层的输出线性在[-1,+1]可以看成是在0值附近分布,均值为0,这样从隐藏层到输出层,数据达到了归一化(*****************)。为了弥补Sigmoid函数和tanh函数的缺点,选择ReLU函数能够保证在z>0时梯度始终为1,从而提高神经网络梯度下降算法的运行速度。进一步弥补ReLU函数的缺点,出现了LeaKy ReLU函数。
- 对于输出层的激活函数,因为二分问题的输出取值为{0,1},所以一般会选择Sigmoid函数作为激活函数。
- 如果是预测问题(***********************)而非分类问题,在输出是连续值的情况下,输出层的激活函数可以使用线性函数。如果输出恒为正值,也可以使用ReLU激活函数。
-
非线性激活函数:根据上述的公式,有下列(因为是线性的,激活函数简化为a=z)展开,这表明如果使用线性激活函数,输出仍是输入的线性组合,即使是包含多层隐藏层的神经网络,只要激活函数是线性的,最终的输出仍然是线性模型,神经网络就没有任何作用了。因此激活函数必须是非线性的。
A [ 2 ] = Z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 2 ] = W [ 2 ] Z [ 1 ] + b [ 2 ] = W [ 2 ] ( W [ 1 ] X + b [ 1 ] ) + b [ 2 ] = ( W [ 2 ] W [ 1 ] ) X + ( + W [ 2 ] b [ 1 ] + b [ 2 ] ) = W ‘ X + b ‘ A^{[2]}=Z^{[2]}=W^{[2]}A^{[1]}+b^{[2]}=W^{[2]}Z^{[1]}+b^{[2]}=W^{[2]}(W^{[1]}X+b^{[1]})+b^{[2]}=(W^{[2]}W^{[1]})X+(+W^{[2]}b^{[1]}+b^{[2]})=W^`X+b^` A[2]=Z[2]=W[2]A[1]+b[2]=W[2]Z[1]+b[2]=W[2](W[1]X+b[1])+b[2]=(W[2]W[1])X+(+W[2]b[1]+b[2])=W‘X+b‘
如果所有隐藏层都使用线性激活函数,只有输出层使用非线性激活函数,那么整个神经网络的结构就类似于一个简单的逻辑回归模型,相当于只使用一个神经元。
四、反向传播
-
神经网络经过前向传播后,接下来可以计算其损失函数。神经网络二分类问题与逻辑回归一样,采用交叉熵损失:
J = − 1 m ∑ y ( i ) l o g a [ 2 ] ( i ) + ( 1 − y ( i ) ) l o g ( 1 − a [ 2 ] ( i ) ) J=-\frac{1}{m}\sum y^{(i)}log a^{[2](i)}+(1-y^{(i)})log(1-a^{[2](i)}) J=−m1∑y(i)loga[2](i)+(1−y(i))log(1−a[2](i)) -
计算交叉熵损失后,就可以及逆行神经网络的反向传播了。反向传播是对神经网络输出层、隐藏层的参数W和b计算偏导数的过程。
-
神经网络代价函数J对 Z [ 2 ] Z^{[2]} Z[2]的偏导数:(*****************************)
d Z [ 2 ] = A [ 2 ] − Y dZ^{[2]}=A^{[2]}-Y dZ[2]=A[2]−Y
根据求偏导法则计算其他偏导数,输出层:
{ d W [ 2 ] = d Z [ 2 ] ⋅ ∂ Z [ 2 ] ∂ W [ 2 ] = 1 m ( A [ 2 ] − Y ) A [ 1 ] T d b [ 2 ] = 1 m ∑ d Z [ 2 ] ( i ) \{{{dW^{[2]}=dZ^{[2]}·\frac{∂Z^{[2]}}{∂W^{[2]}}}=\frac{1}{m}(A^{[2]}-Y)A^{[1]T} \atop db^{[2]}=\frac{1}{m}\sum dZ^{[2](i)}} {db[2]=m1∑dZ[2](i)dW[2]=dZ[2]⋅∂W[2]∂Z[2]=m1(A[2]−Y)A[1]T
隐藏层:
{ d Z [ 1 ] = d Z [ 2 ] ⋅ ∂ Z [ 2 ] ∂ A [ 1 ] ⋅ ∂ A [ 1 ] ∂ Z [ 1 ] = W [ 2 ] T d Z [ 2 ] ∗ g ‘ ( Z [ 1 ] ) d W [ 1 ] = d Z [ 1 ] ⋅ ∂ Z [ 1 ] ∂ W [ 1 ] = 1 m d Z [ 1 ] X T d b [ 1 ] = 1 m ∑ d Z [ 1 ] ( i ) \{{dZ^{[1]}=dZ^{[2]}·\frac{∂Z^{[2]}}{∂A^{[1]}}·\frac{∂A^{[1]}}{∂Z^{[1]}}=W^{[2]T}dZ^{[2]}*g^`(Z^{[1]}) \atop {dW^{[1]}=dZ^{[1]}·\frac{∂Z^{[1]}}{∂W^{[1]}}=\frac{1}{m}dZ^{[1]}X^T \atop db^{[1]}=\frac{1}{m}\sum dZ^{[1](i)}}} {db[1]=m1∑dZ[1](i)dW[1]=dZ[1]⋅∂W[1]∂Z[1]=m1dZ[1]XTdZ[1]=dZ[2]⋅∂A[1]∂Z[2]⋅∂Z[1]∂A[1]=W[2]TdZ[2]∗g‘(Z[1])
其中*表示点乘,`表示激活函数的导数。 -
总结:
五、更新参数
完成反向传播后得到了各层的参数梯度dW和db,接下来需要根据梯度下降算法对参数W和b进行更新。
{
W
[
1
]
=
W
[
1
]
−
η
⋅
d
W
[
1
]
b
[
1
]
=
b
[
1
]
−
η
⋅
d
b
[
1
]
W
[
2
]
=
W
[
2
]
−
η
⋅
d
W
[
2
]
b
[
2
]
=
b
[
2
]
−
η
⋅
d
b
[
2
]
\{{{W^{[1]}=W^{[1]}-\eta·dW^{[1]} \atop b^{[1]}=b^{[1]}-\eta·db^{[1]}} \atop {W^{[2]}=W^{[2]}-\eta·dW^{[2]} \atop b^{[2]}=b^{[2]}-\eta·db^{[2]}}}
{b[2]=b[2]−η⋅db[2]W[2]=W[2]−η⋅dW[2]b[1]=b[1]−η⋅db[1]W[1]=W[1]−η⋅dW[1]
至此经过前向传播、反向传播、更新参数后,神经网络的一次训练就完成了。
六、初始化
神经网络中的参数W和b的初始化,在逻辑回归模型中,参数W和b一般全部初始化为0即可,**神经网络中却不能这样做!**因为如果初始化为0,那么隐藏层各个神经元的dW都一样,这样会导致隐藏层3个神经元对应的权重每次迭代更新都会得到完全相同的结果,造成隐藏层3个神经元完全对称,效果相同,隐藏层多个神经元就没有意义了。
因此神经网络的权重系数W一般不会初始化为零,可以进行**随机初始化。**但是偏置项系数b一般可以初始化为0,不会影响神经网络的训练效果。
七、神经网络的Python实现
-
准备数据:采用与上一节中相同的数据集。
-
参数初始化:按照第六部分的初始化方式进行:
def initialize_parameters(n_x, n_h, n_y): """ 函数输入: n_x:输入层维度 n_h:隐藏层神经元个数 n_y:输出层神经元个数 函数输出; params:存储参数的字典,W1,b1, W2, b2 """ np.random.seed(0) #设置随机种子 #参数初始化 W1 = np.random.randn(n_h, n_x) b1 = np.zeros((n_h, 1)) W2 = np.random.randn(n_y, n_h) b2 = np.zeros((n_y, 1)) parameters = { 'W1':W1, 'b1':b1, 'W2':W2, 'b2':b2 } return parameters
-
前向传播:隐藏层的激活函数选择tanh函数(NumPy中自带),输出层的激活函数选择Sigmoid函数。
def sigmoid(z): """ 函数输入: z:激活函数输入,神经元线性输出 函数输出: a:激活函数输出,神经元非线性输出 """ a = 1/(1+np.exp(-z)) return a #定义前向传播 def forward_propagation(X, parameters): """ 函数输入: X:神经网络输入 cache:神经网络参数 函数输出: A2:神经网络输出 cache:缓存,存储中间变量:Z1, A1, Z2, A2 """ #神经网络参数 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={ 'Z1':Z1, 'A1':A1, 'Z2':Z2, 'A2':A2 } return A2,cache
-
交叉熵损失:与上一节中逻辑回归一样。
def compute_loss(A2, Y): """ 函数输入: A2:神经网络输出 Y:样本真实标签 函数输出: cost:神经网络交叉熵损失 """ #样本个数 m = Y.shape[1] cross_entropy = -(Y*np.log(A2)+(1-Y)*np.log(1-A2)) cost = 1.0/m*np.sum(cross_entropy) return cost
-
反向传播:
def back_propagation(X, Y, parameters, cache): """ 函数输出: X:神经网络输入 Y:样本真实标签 parameters:网络参数 cache:缓存,存储中间变量:Z1, A1, Z2, A2 函数输入: grads:神经网络参数梯度 """ #样本个数 m = X.shape[1] #神经网络参数 W1 = parameters['W1'] b1 = parameters['b1'] W2 = parameters['W2'] b2 = parameters['b2'] #中间变量 Z1 = cache['Z1'] A1 = cache['A1'] Z2 = cache['Z2'] A2 = cache['A2'] #计算梯度 dZ2 = A2 -Y dW2 = 1.0/m*np.dot(dZ2, A1.T) db2 = 1.0/m*np.sum(dZ2, axis=1, keepdims=True) dZ1 = np.dot(W2.T, dZ2)*(1-np.power(A1, 2)) dW1 = 1.0/m*np.dot(dZ1, X.T) db1 = 1.0/m*np.sum(dZ1, axis=1, keepdims=True) grads = { 'dW1':dW1, 'db1':db1, 'dW2':dW2, 'db2':db2 } return grads
-
更新参数:根据梯度下降算法更新参数。
def update_parameters(parameters, grads, learning_rate=0.1): """ 函数输出: parameters:网络参数 grads:神经网络参数梯度 函数输入: parameters:网络参数 """ #神经网络参数 W1 = parameters['W1'] b1 = parameters['b1'] W2 = parameters['W2'] b2 = parameters['b2'] #神经网络参数梯度 dW1 = grads['dW1'] db1 = grads['db1'] dW2 = grads['dW2'] db2 = 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
-
构建整个神将网络模型:将前面定义的几个模块整合起来。
def nn_model(X, Y, n_h=3, num_iterations=200, learning_rate=0.1): """ 函数输入: X:神经网络输入 Y:样本真实标签 n_h:隐藏层神经元个数 num_iterations:训练次数 learning_rate:学习率 函数输出: parameters:训练完成后的网络参数 """ #定义网络 n_x=X.shape[0] n_y=1 #参数初始化 parameters = initialize_parameters(n_x, n_h,n_y) #迭代训练 for i in range(num_iterations): #正向传播 A2, cache = forward_propagation(X, parameters) #计算交叉熵损失 cost = compute_loss(A2, Y) #反向传播 grads = back_propagation(X, Y, parameters, cache) #更新参数 parameters = update_parameters(parameters, grads, learning_rate) #print if (i+1)%20==0: print('Iteration:%d, cost=%f'%(i+1, cost)) return parameters
-
训练:选择隐藏层神经元个数为3,迭代训练次数为500,学习率设置为0.2。
parameters = nn_model(X, Y, n_h=3, num_iterations=500, learning_rate=0.2)
-
预测:使用模型对数据集进行分类。
def predict(X, parameters): """ 函数输入: X:神经网络输入 parameters:训练完成后的网络参数 函数输出: Y_pred:预测样本标签 """ #神经网络参数 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) #预测标签 Y_pred = np.zeros((1,X.shape[1])) #初始化Y_pred Y_pred[A2 > 0.5]=1 #Y_hat大于0.5的预测为正值(输出层使用的Sigmoid) return Y_pred #对数据及进行预测,并计算准确率 accuracy = np.mean(Y_pred == Y) print(accuracy)
还可以绘制决策边界,可视化分类效果:
from matplotlib.colors import ListedColormap x_min, x_max = X[0, :].min() - 0.5,X[0, :].max() + 0.5 y_min, y_max = X[1, :].min() - 0.5,X[1, :].max() + 0.5 step = 0.001 xx,yy=np.meshgrid(np.arange(x_min,x_max,step),np.arange(y_min,y_max,step)) Z = predict(np.c_[xx.ravel(),yy.ravel()].T,parameters) Z = Z.reshape(xx.shape) plt.contourf(xx,yy,Z,cmap=plt.cm.Spectral) #绘制边界 #负类 plt.scatter(X[0,Y[0,:]==0],X[1,Y[0,:]==0],c='g',marker='s',label='负类') #正类 plt.scatter(X[0,Y[0,:]==1],X[1,Y[0,:]==1],c='y',marker='o',label='正类') plt.legend() plt.show()
-
全部代码:
import sklearn.datasets import numpy as np from matplotlib.colors import ListedColormap import matplotlib.pyplot as plt np.random.seed(1) #设置随机种子 #导入make_moon数据集,样本个数m=200,噪声标准差为0.2 X, Y = sklearn.datasets.make_moons(n_samples=200, noise=.2) #X shape:[2, 200], Y shape:[1, 200] X, Y = X.T, Y.reshape(1, Y.shape[0]) #负类 plt.scatter(X[0, Y[0,:]==0],X[1, Y[0,:]==0], c='r', marker='s') #正类 plt.scatter(X[0, Y[0,:]==1],X[1, Y[0,:]==1], c='b', marker='o') plt.show() def initialize_parameters(n_x, n_h, n_y): """ 函数输入: n_x:输入层维度 n_h:隐藏层神经元个数 n_y:输出层神经元个数 函数输出; params:存储参数的字典,W1,b1, W2, b2 """ np.random.seed(0) #设置随机种子 #参数初始化 W1 = np.random.randn(n_h, n_x) b1 = np.zeros((n_h, 1)) W2 = np.random.randn(n_y, n_h) b2 = np.zeros((n_y, 1)) parameters = { 'W1':W1, 'b1':b1, 'W2':W2, 'b2':b2 } return parameters def sigmoid(z): """ 函数输入: z:激活函数输入,神经元线性输出 函数输出: a:激活函数输出,神经元非线性输出 """ a = 1/(1+np.exp(-z)) return a #定义前向传播 def forward_propagation(X, parameters): """ 函数输入: X:神经网络输入 cache:神经网络参数 函数输出: A2:神经网络输出 cache:缓存,存储中间变量:Z1, A1, Z2, A2 """ #神经网络参数 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={ 'Z1':Z1, 'A1':A1, 'Z2':Z2, 'A2':A2 } return A2,cache def compute_loss(A2, Y): """ 函数输入: A2:神经网络输出 Y:样本真实标签 函数输出: cost:神经网络交叉熵损失 """ #样本个数 m = Y.shape[1] cross_entropy = -(Y*np.log(A2)+(1-Y)*np.log(1-A2)) cost = 1.0/m*np.sum(cross_entropy) return cost def back_propagation(X, Y, parameters, cache): """ 函数输出: X:神经网络输入 Y:样本真实标签 parameters:网络参数 cache:缓存,存储中间变量:Z1, A1, Z2, A2 函数输入: grads:神经网络参数梯度 """ #样本个数 m = X.shape[1] #神经网络参数 W1 = parameters['W1'] b1 = parameters['b1'] W2 = parameters['W2'] b2 = parameters['b2'] #中间变量 Z1 = cache['Z1'] A1 = cache['A1'] Z2 = cache['Z2'] A2 = cache['A2'] #计算梯度 dZ2 = A2 -Y dW2 = 1.0/m*np.dot(dZ2, A1.T) db2 = 1.0/m*np.sum(dZ2, axis=1, keepdims=True) dZ1 = np.dot(W2.T, dZ2)*(1-np.power(A1, 2)) dW1 = 1.0/m*np.dot(dZ1, X.T) db1 = 1.0/m*np.sum(dZ1, axis=1, keepdims=True) grads = { 'dW1':dW1, 'db1':db1, 'dW2':dW2, 'db2':db2 } return grads def update_parameters(parameters, grads, learning_rate=0.1): """ 函数输出: parameters:网络参数 grads:神经网络参数梯度 函数输入: parameters:网络参数 """ #神经网络参数 W1 = parameters['W1'] b1 = parameters['b1'] W2 = parameters['W2'] b2 = parameters['b2'] #神经网络参数梯度 dW1 = grads['dW1'] db1 = grads['db1'] dW2 = grads['dW2'] db2 = 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 def nn_model(X, Y, n_h=3, num_iterations=200, learning_rate=0.1): """ 函数输入: X:神经网络输入 Y:样本真实标签 n_h:隐藏层神经元个数 num_iterations:训练次数 learning_rate:学习率 函数输出: parameters:训练完成后的网络参数 """ #定义网络 n_x=X.shape[0] n_y=1 #参数初始化 parameters = initialize_parameters(n_x, n_h,n_y) #迭代训练 for i in range(num_iterations): #正向传播 A2, cache = forward_propagation(X, parameters) #计算交叉熵损失 cost = compute_loss(A2, Y) #反向传播 grads = back_propagation(X, Y, parameters, cache) #更新参数 parameters = update_parameters(parameters, grads, learning_rate) #print if (i+1)%20==0: print('Iteration:%d, cost=%f'%(i+1, cost)) return parameters parameters = nn_model(X, Y, n_h=3, num_iterations=500, learning_rate=0.2) def predict(X, parameters): """ 函数输入: X:神经网络输入 parameters:训练完成后的网络参数 函数输出: Y_pred:预测样本标签 """ #神经网络参数 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) #预测标签 Y_pred = np.zeros((1, X.shape[1])) #初始化Y_pred Y_pred[A2 > 0.5]=1 #Y_hat大于0.5的预测为正值(输出层使用的Sigmoid) return Y_pred #对数据集进行预测,并计算准确率 Y_pred = predict(X, parameters) accuracy = np.mean(Y_pred == Y) print(accuracy) x_min, x_max = X[0, :].min() - 0.5,X[0, :].max() + 0.5 y_min, y_max = X[1, :].min() - 0.5,X[1, :].max() + 0.5 step = 0.001 xx,yy=np.meshgrid(np.arange(x_min,x_max,step),np.arange(y_min,y_max,step)) Z = predict(np.c_[xx.ravel(),yy.ravel()].T,parameters) Z = Z.reshape(xx.shape) plt.contourf(xx,yy,Z,cmap=plt.cm.Spectral) #绘制边界 #负类 plt.scatter(X[0,Y[0,:]==0],X[1,Y[0,:]==0],c='g',marker='s',label='负类') #正类 plt.scatter(X[0,Y[0,:]==1],X[1,Y[0,:]==1],c='y',marker='o',label='正类') plt.legend() plt.show()