# 带有一个隐藏层的平面数据分类

## 预备知识

```import numpy as np
import matplotlib.pyplot as plt
from testCases import *
import sklearn
import sklearn.datasets
import sklearn.linear_model
from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets

np.random.seed(1) #设置一个固定的随机种子，以保证接下来的步骤中我们的结果是一致的。```

```def layer_sizes_test_case():
np.random.seed(1)
X_assess = np.random.randn(5, 3)
Y_assess = np.random.randn(2, 3)
return X_assess, Y_assess

def initialize_parameters_test_case():
n_x, n_h, n_y = 2, 4, 1
return n_x, n_h, n_y

def forward_propagation_test_case():
np.random.seed(1)
X_assess = np.random.randn(2, 3)

parameters = {'W1': np.array([[-0.00416758, -0.00056267],
[-0.02136196,  0.01640271],
[-0.01793436, -0.00841747],
[ 0.00502881, -0.01245288]]),
'W2': np.array([[-0.01057952, -0.00909008,  0.00551454,  0.02292208]]),
'b1': np.array([[ 0.],
[ 0.],
[ 0.],
[ 0.]]),
'b2': np.array([[ 0.]])}

return X_assess, parameters```

```import sklearn
import sklearn.datasets
import sklearn.linear_model
from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets```

### 分析数据集

`X, Y = load_planar_dataset()`

`from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets`

```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```

```shape_X = X.shape
shape_Y = Y.shape
m = Y.shape[1]  # 训练集里面的数量

print ("X的维度为: " + str(shape_X))
print ("Y的维度为: " + str(shape_Y))
print ("数据集里面的数据有：" + str(m) + " 个")```

```X的维度为: (2, 400)
Y的维度为: (1, 400)

```plt.scatter(X[0, :], X[1, :], c=Y, s=40, cmap=plt.cm.Spectral) #绘制散点图
plt.show()```

## 编写代码

### 定义神经网络的结构

#### 定义神经网络层数

```def layer_sizes(X , Y):
"""
参数：
X - 输入数据集,维度为（输入的数量，训练/测试的数量）
Y - 标签，维度为（输出的数量，训练/测试数量）

返回：
n_x - 输入层的数量
n_h - 隐藏层的数量
n_y - 输出层的数量
"""
n_x = X.shape[0] #输入层
n_h = 4 #，隐藏层，硬编码为4
n_y = Y.shape[0] #输出层

return (n_x,n_h,n_y)```

```#测试layer_sizes
print("=========================测试layer_sizes=========================")
X_asses , Y_asses = layer_sizes_test_case()
(n_x,n_h,n_y) =  layer_sizes(X_asses,Y_asses)
print("输入层的节点数量为: n_x = " + str(n_x))
print("隐藏层的节点数量为: n_h = " + str(n_h))
print("输出层的节点数量为: n_y = " + str(n_y))```

```def layer_sizes_test_case():
np.random.seed(1)
X_assess = np.random.randn(5, 3)
Y_assess = np.random.randn(2, 3)
return X_assess, Y_assess```

```=========================测试layer_sizes=========================

#### 初始化参数

```def initialize_parameters( n_x , n_h ,n_y):

np.random.seed(2) #指定一个随机种子，以便你的输出与我们的一样。
W1 = np.random.randn(n_h,n_x) * 0.01
b1 = np.zeros(shape=(n_h, 1))
W2 = np.random.randn(n_y,n_h) * 0.01
b2 = np.zeros(shape=(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```

n_x是第一层，n_h是第二层，n_y是第三层

```w和b的维数问题

```#测试initialize_parameters
print("=========================测试initialize_parameters=========================")
n_x , n_h , n_y = initialize_parameters_test_case()
parameters = initialize_parameters(n_x , n_h , n_y)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))```

```def initialize_parameters_test_case():
n_x, n_h, n_y = 2, 4, 1
return n_x, n_h, n_y```

```=========================测试initialize_parameters=========================
W1 = [[-0.00416758 -0.00056267]
[-0.02136196  0.01640271]
[-0.01793436 -0.00841747]
[ 0.00502881 -0.01245288]]
b1 = [[ 0.]
[ 0.]
[ 0.]
[ 0.]]
W2 = [[-0.01057952 -0.00909008  0.00551454  0.02292208]]
b2 = [[ 0.]]```

### 向前传播

```def forward_propagation( X , parameters ):
"""
参数：
X - 维度为（n_x，m）的输入数据。
parameters - 初始化函数（initialize_parameters）的输出

返回：
A2 - 使用sigmoid()函数计算的第二次激活后的数值
cache - 包含“Z1”，“A1”，“Z2”和“A2”的字典类型变量
"""
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
#前向传播计算A2
Z1 = np.dot(W1 , X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2 , A1) + b2
A2 = sigmoid(Z2)
#使用断言确保我的数据格式是正确的
assert(A2.shape == (1,X.shape[1]))
cache = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}

return (A2, cache)```

```def forward_propagation_test_case():
np.random.seed(1)
X_assess = np.random.randn(2, 3)

parameters = {'W1': np.array([[-0.00416758, -0.00056267],
[-0.02136196,  0.01640271],
[-0.01793436, -0.00841747],
[ 0.00502881, -0.01245288]]),
'W2': np.array([[-0.01057952, -0.00909008,  0.00551454,  0.02292208]]),
'b1': np.array([[ 0.],
[ 0.],
[ 0.],
[ 0.]]),
'b2': np.array([[ 0.]])}

return X_assess, parameters```
```#测试forward_propagation
print("=========================测试forward_propagation=========================")
X_assess, parameters = forward_propagation_test_case()
A2, cache = forward_propagation(X_assess, parameters)
print(cache["Z1"], cache["A1"], cache["Z2"], cache["A2"])```

```=========================测试forward_propagation=========================
[[-0.00616586  0.0020626   0.0034962 ]
[-0.05229879  0.02726335 -0.02646869]
[-0.02009991  0.00368692  0.02884556]
[ 0.02153007 -0.01385322  0.02600471]] [[-0.00616578  0.0020626   0.00349619]
[-0.05225116  0.02725659 -0.02646251]
[-0.02009721  0.0036869   0.02883756]
[ 0.02152675 -0.01385234  0.02599885]] [[ 0.00092281 -0.00056678  0.00095853]] [[0.5002307  0.49985831 0.50023963]]```

### 损失函数的计算

```def compute_cost(A2,Y,parameters):
"""
计算方程（6）中给出的交叉熵成本，

参数：
A2 - 使用sigmoid()函数计算的第二次激活后的数值
Y - "True"标签向量,维度为（1，数量）
parameters - 一个包含W1，B1，W2和B2的字典类型的变量

返回：
成本 - 交叉熵成本给出方程（13）
"""

m = Y.shape[1]
W1 = parameters["W1"]
W2 = parameters["W2"]

#计算成本
logprobs = 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```

```#测试compute_cost
print("=========================测试compute_cost=========================")
A2 , Y_assess , parameters = compute_cost_test_case()
print("cost = " + str(compute_cost(A2,Y_assess,parameters)))```
```=========================测试compute_cost=========================
cost = 0.6929198937761266```

### 反向传播

```def backward_propagation(parameters,cache,X,Y):
"""
使用上述说明搭建反向传播函数。

参数：
parameters - 包含我们的参数的一个字典类型的变量。
cache - 包含“Z1”，“A1”，“Z2”和“A2”的字典类型的变量。
X - 输入数据，维度为（2，数量）
Y - “True”标签，维度为（1，数量）

返回：
"""
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)
dZ1 = np.multiply(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 }

```dZ2= A2 - Y
dW2 = (1 / m) * np.dot(dZ2, A1.T)```

`    db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)`

db2是(1,1)

`    dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))`

1-np.power(A1,2)这个就是tanh的导数，multiply前后两个值是相同的维度

```    dW1 = (1 / m) * np.dot(dZ1, X.T)
db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)```

dW1(当前神经元，输入特征值)
db1(当前神经元个数，1)

```#测试backward_propagation
print("=========================测试backward_propagation=========================")
parameters, cache, X_assess, Y_assess = backward_propagation_test_case()

grads = backward_propagation(parameters, cache, X_assess, Y_assess)
print ("dW1 = "+ str(grads["dW1"]))
print ("db1 = "+ str(grads["db1"]))
print ("dW2 = "+ str(grads["dW2"]))
print ("db2 = "+ str(grads["db2"]))```

### 修改参数

```def update_parameters(parameters,grads,learning_rate=1.2):
"""
使用上面给出的梯度下降更新规则更新参数

参数：
parameters - 包含参数的字典类型的变量。
learning_rate - 学习速率

返回：
parameters - 包含更新参数的字典类型的变量。
"""
W1,W2 = parameters["W1"],parameters["W2"]
b1,b2 = parameters["b1"],parameters["b2"]

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 update_parameters_test_case():
parameters = {'W1': np.array([[-0.00615039,  0.0169021 ],
[-0.02311792,  0.03137121],
[-0.0169217 , -0.01752545],
[ 0.00935436, -0.05018221]]),
'W2': np.array([[-0.0104319 , -0.04019007,  0.01607211,  0.04440255]]),
'b1': np.array([[ -8.97523455e-07],
[  8.15562092e-06],
[  6.04810633e-07],
[ -2.54560700e-06]]),
'b2': np.array([[  9.14954378e-05]])}

grads = {'dW1': np.array([[ 0.00023322, -0.00205423],
[ 0.00082222, -0.00700776],
[-0.00031831,  0.0028636 ],
[-0.00092857,  0.00809933]]),
'dW2': np.array([[ -1.75740039e-05,   3.70231337e-03,  -1.25683095e-03,
-2.55715317e-03]]),
'db1': np.array([[  1.05570087e-07],
[ -3.81814487e-06],
[ -1.90155145e-07],
[  5.46467802e-07]]),
'db2': np.array([[ -1.08923140e-05]])}

```#测试update_parameters
print("=========================测试update_parameters=========================")
parameters, grads = update_parameters_test_case()
parameters = update_parameters(parameters, grads)

print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

=========================测试update_parameters=========================
W1 = [[-0.00643025  0.01936718]
[-0.02410458  0.03978052]
[-0.01653973 -0.02096177]
[ 0.01046864 -0.05990141]]
b1 = [[-1.02420756e-06]
[ 1.27373948e-05]
[ 8.32996807e-07]
[-3.20136836e-06]]
W2 = [[-0.01041081 -0.04463285  0.01758031  0.04747113]]
b2 = [[0.00010457]]```

### 整合到一起

```def nn_model(X,Y,n_h,num_iterations,print_cost=False):
"""
参数：
X - 数据集,维度为（2，示例数）
Y - 标签，维度为（1，示例数）
n_h - 隐藏层的数量
num_iterations - 梯度下降循环中的迭代次数
print_cost - 如果为True，则每1000次迭代打印一次成本数值

返回：
parameters - 模型学习的参数，它们可以用来进行预测。
"""

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)
W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]

for i in range(num_iterations):
A2 , cache = forward_propagation(X,parameters)
cost = compute_cost(A2,Y,parameters)
parameters = update_parameters(parameters,grads,learning_rate = 0.5)

if print_cost:
if i%1000 == 0:
print("第 ",i," 次循环，成本为："+str(cost))
return parameters```

### 测试函数

```def predict(parameters,X):
"""
使用学习的参数，为X中的每个示例预测一个类

参数：
parameters - 包含参数的字典类型的变量。
X - 输入数据（n_x，m）

返回
predictions - 我们模型预测的向量（红色：0 /蓝色：1）

"""
A2 , cache = forward_propagation(X,parameters)
predictions = np.round(A2)

return predictions```

### 运行的函数

```parameters = nn_model(X, Y, n_h = 4, num_iterations=10000, print_cost=True)

#绘制边界
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y)
plt.title("Decision Boundary for hidden layer size " + str(4))

predictions = predict(parameters, X)
print ('准确率: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')```