0、引言
在感知机一节中讲到感知机是一种线性模型,存在的缺点是很难解决非线性问题,比如异或(XOR)就是一种典型的线性不可分的问题,因此有了神经网络,通过在感知机的结构中添加隐藏层来拟合非线性问题。
1、原理
后续补充。。。。。。。。。。。。。。。
2、代码实现
神经网络的构建过程:
- 定义神经网络结构(指定传输层、隐藏层、输出层大小);
- 初始化模型参数;
- 循环操作:执行前向传播/计算损失/执行反后向传播/权值矩阵
常见参数优化算法(如:梯度下降法、随机梯度下降、牛顿法、拟牛顿法、Adam)数学原理可以看下以下的博客:
https://blog.csdn.net/Zjhao666/article/details/88402518
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.gam.tests.test_gam import sigmoid
#生成数据集
def create_dataset():
np.random.seed(1) #随机数种子,可以在某个种子堆中调用相同的额随机数值
#数据量
m = 400
#每个标签的实例数
N = int(m/2)
#数据维度
D = 2
X = np.zeros((m, D)) #400*2
Y = np.zeros((m,1), dtype = 'uint8')
a = 4
for j in range(2):
ix = range(N*j, N*(j+1))
#linspace(a,b,n) 在[2,3]上生成等间隔的N个数
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
#np.r_是按列连接两个矩阵,就是把两矩阵上下相加,要求列数相等。
#np.c_是按行连接两个矩阵,就是把两矩阵左右相加,要求行数相等。
X[ix] = np.c_[r * np.sin(t), r * np.cos(t)]
Y[ix] = j
X = X.T
Y = Y.T
return X, Y
#定义一个单隐藏层的神经网络
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)
#初始化模型参数
def initialize_parameters(n_x, n_h, n_y):
W1 = np.random.randn(n_h, n_x) * 0.01
b1 = np.zeros((n_h, 1))
W2 = np.random.randn(n_y, n_h) * 0.01
b2 = np.zeros((n_y, 1))
#错误检查,判断
assert (W1.shape == (n_h, n_x))
assert (b1.shape == (n_h, 1))
assert (W2.shape == (n_y, n_h))
assert (b2.shape == (n_y, 1))
#封装成字典
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
#前向传播
def forward_propagation(X, parameters):
# 获取各参数初始值
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']
# 执行前向计算
Z1 = np.dot(W1, X) + b1 #dot矩阵点乘
A1 = np.tanh(Z1) #隐藏层使用tanh激活
Z2 = np.dot(W2, A1) + b2
A2 = sigmoid(Z2) #隐藏层使用sigmoid激活,作为输出y
assert(A2.shape == (1, X.shape[1]))
#保存前向传播的结果
cache = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}
return A2, cache
#计算当前训练损失(交叉熵损失)
def compute_cost(A2, Y):
# 训练样本量
m = Y.shape[1]
# 计算交叉熵损失
logprobs = np.multiply(np.log(A2),Y) + np.multiply(np.log(1-A2), 1-Y)
cost = -1/m * np.sum(logprobs)
# 维度压缩
cost = np.squeeze(cost)
assert(isinstance(cost, float))
return cost
#反向传播(梯度计算)
def backward_propagation(parameters, cache, X, Y):
m = X.shape[1]
# 获取W1和W2
W1 = parameters['W1']
W2 = parameters['W2']
# 获取A1和A2
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)
dZ1 = np.dot(W2.T, dZ2)*(1-np.power(A1, 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
#更新权值,这里学习率a初始化为1.2
def update_parameters(parameters, grads, learning_rate=1.2):
# 获取参数
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 -= dW1 * learning_rate
b1 -= db1 * learning_rate
W2 -= dW2 * learning_rate
b2 -= db2 * learning_rate
#保存新参数
parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters
#组合成model,迭代次数为10000
def nn_model(X, Y, n_h, num_iterations=10000, print_cost=False):
np.random.seed(3)
n_x = layer_sizes(X, Y)[0]
n_y = layer_sizes(X, Y)[2]
# 初始化模型参数
parameters = initialize_parameters(n_x, n_h, n_y)
# 梯度下降和参数更新循环
for i in range(0, num_iterations):
# 前向传播计算
A2, cache = forward_propagation(X, parameters)
# 计算当前损失
cost = compute_cost(A2, Y)
# 反向传播
grads = backward_propagation(parameters, cache, X, Y)
# 参数更新
parameters = update_parameters(parameters, grads, learning_rate=1.2)
# 打印损失
if print_cost and i % 1000 == 0:
print("Cost after iteration %i: %f" % (i, cost))
return parameters
# 预测函数
def predict(parameters, X):
A2, cache = forward_propagation(X, parameters)
predictions = (A2>0.5)
return predictions
#绘制决策边界
def plot_decision_boundary(model, X, y):
#边界最大最小值
x_min, x_max = X[0, :].min() - 1, X[0, :].max() + 1
y_min, y_max = X[1, :].min() - 1, X[1, :].max() + 1
h = 0.01
#网格图大小
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = model(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
plt.ylabel('x2')
plt.xlabel('x1')
plt.scatter(X[0, :], X[1, :], c=y, cmap=plt.cm.Spectral)
#绘图
def plot_Decision_Answer(X, Y):
plt.figure(figsize=(16, 32))
#设置不同隐藏层大小
hidden_layer_sizes = [1, 2, 3, 4, 5, 10, 20]
for i, n_h in enumerate(hidden_layer_sizes):
plt.subplot(5, 2, i+1)
plt.title('Hidden Layer of size %d' % n_h)
#加载训练模型
parameters = nn_model(X, Y, n_h = 4,
num_iterations = 10000,
print_cost=False)
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y[0])
#预测
predictions = predict(parameters, X)
#预测精度计算
accuracy = float((np.dot(Y,predictions.T) + np.dot(1-Y,1-predictions.T))/float(Y.size)*100)
print ("Accuracy for {} hidden units: {}%".format(n_h, accuracy))
plt.show()
def main():
X, Y = create_dataset()
# 数据可视化
plt.scatter(X[0, :], X[1, :], c=Y[0], s=40, cmap=plt.cm.Spectral)
# plt.show()
#神经网络
plot_Decision_Answer(X, Y)
if __name__ == '__main__':
main()
参考资料:
[1]https://blog.csdn.net/Zjhao666/article/details/88402518
[2]https://github.com/luwill/machine-learning-code-writing