神经网络
构建一个最简单的包括输入层,一层隐藏层和输出层的基础神经网络模型
1.准备数据,使用sklearn.datasets.make_moons这个数据集来测试:
np.random.seed(1)
X,Y = sklearn.datasets.make_moons(n_samples=200,noise=.2)
X,Y = X.T, Y.reshape(1, Y.shape[0])
m = X.shape[1] #样本个数
dim = X.shape[0] #特征维度
2.参数初始化
def initialize_parameters(n_x, n_h, n_y):
"""
函数输出
:param n_x: 输入层维度
:param n_h: 隐藏层神经元个数
:param n_y: 输出层神经元个数
:return:
: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
3.前向传播
def sigmoid(x):
"""
函数输入:
-x: sigmoid 函数输入
函数输出:
-y: sigmoid 函数输出
:param x:
:return:
"""
y = 1/(1+np.exp(-x))
return y
#定义神经网络的前向传播
def forward_propagation(X, parameters):
"""
函数输出
:param X: 神经网络输入
:param parameters: 神经网络参数
:return:
-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
4.交叉熵损失部分
def compute_loss(A2, Y):
"""
函数输入
:param A2: 神经网络输出
:param Y: 样本真实标签
:return:
-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
5.反向传播部分
def back_propagation(X, Y, parameters, cache):
"""
函数输入
:param X: 神经网络输入
:param Y: 样本真实标签
:param parameters: 网络参数
:param cache: 缓存cache,存储中间变量Z1, A1, Z2, A2
:return:
- grade: 神经网络参数梯度
"""
# 样本个数
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
6.梯度下降更新参数
def updates_parameters(parameters, grads, learning_rate = 0.1):
"""
函数输入
:param parameters: 网络参数
:param grads: 神经网络参数梯度
:param learning_rate: 学习率
:return:
-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
7.构建网络模型
def nn_model(X, Y, n_h, num_iterations = 200, learning_rate=0.1):
"""
函数输入
:param X:神经网络输入
:param Y: 样本真实标签
:param n_h: 隐藏层神经元个数
:param num_iterations: 训练次数
:param learning_rate: 学习率
:return:
-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 = updates_parameters(parameters, grads, learning_rate)
if (i+1)%20 == 0:
print('Iteration: %d, cost = %f' % (i+1, cost))
return parameters
8.预测与训练
parameters = nn_model(X, Y, n_h=3, num_iterations=50000, learning_rate=0.1)
#预测
def predict(X, parameters):
"""
函数输入
:param X: 神经网络输入
:param parameters: 训练完的网络参数模型
:return:
-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[A2>0.5] = 1
return Y_pred
Y_pred = predict(X,parameters)
print(np.mean(Y_pred==Y))
9.可视化结果与比较
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()
传统逻辑回归预测结果
可以看出,逻辑回归所得到的线性分类结果准确率是远远不如神经网络的非线性分类结果