第一周概论
基础神经网络
- 不规定,神经元节点代表的意义,让计算机自己安排,需要提供大量的数据,x与y进行拟合。
分别是标准神经网络,卷积神经网络(图片),循环神经网络(时间),
结构化数据(表格),非结构化数据(音频,图片)
第二周神经网络基础
- 学习神经网络计算,通过logistics回归函数(二分分类)为什么可以分为前向传播和反向传播。
- 本周设计神经网络进行 图片中猫的查找
- 后期用的字母含义 :
m -训练集的大小或者训练样本的数量、(x,y)表示example 。 x.shape(Python语句显示维度)
-具体例子:
给定图片x,辨别图片中是否是猫,其实就是 判断y尖= P(y=1|x)(猫的概率)。
学习参数W,B (logistics回归模型)
定义损失误差函数 error function L ,用于衡量单个样本在训练上的表现,误差函数越小越好。
定义成本函数 Cost function J, 用于衡量全体样本在训练上的表现
- 梯度下降法
我们在某一点,往导数小的地方进行,每一步是一次迭代,最终通过多次迭代到最小的地方。
logistic 回归函数的梯度下降法 :
算法实现流程
应用两次for循环,大数据时效率低,才用向量化(Vectorization),来替换for循环,提升在大量代码时候的效率
- 非向量化
z= 0 for i in range (n-x) : z+= w[i]*x[i] +b
- 向量化
z = np.dot(w,x)+ b
- 这里放一张函数图:
进行猫的图片识别:
流程图如下图所示:
- 第一步:处理图片数据,图片数据
import numpy as np
import matplotlib.pyplot as plt
import h5py
from lr_utils import load_dataset
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()
# 分别是训练集里面的图像数据(本训练集有209张64x64的图像)。训练集的图像对应的分类值(【0 | 1】,0表示不是猫,1表示是猫)。
# 测试集里面的图像数据(本训练集有50张64x64的图像)。测试集的图像对应的分类值(【0 | 1】,0表示不是猫,1表示是猫)。
# classes : 保存的是以bytes类型保存的两个字符串数据,数据为:[b’non-cat’ b’cat’]。
#index = 25
#plt.imshow(train_set_x_orig[index])
# train_set_x_orig 这个图像数据本身就是一个 (m_train , num_px ,num_px ,3)的一个数组
m_train = train_set_y.shape[1] # 训练集图片数量
m_test = test_set_y.shape[1] # 测试集图片数量
num_px = train_set_x_orig.shape[1] # 图片高度宽度均为64*64
print("训练集的数量: m_train = " + str(m_train))
print("测试集的数量 : m_test = " + str(m_test))
print("每张图片的宽/高 : num_px = " + str(num_px))
print("每张图片的大小 : (" + str(num_px) + ", " + str(num_px) + ", 3)")
print("训练集_图片的维数 : " + str(train_set_x_orig.shape))
print("训练集_标签的维数 : " + str(train_set_y.shape))
print("测试集_图片的维数: " + str(test_set_x_orig.shape))
print("测试集_标签的维数: " + str(test_set_y.shape))
# 把维度为(64,64,3)的numpy数组重新构造为(64 x 64 x 3,1)的数组,
# 要乘以3的原因是每张图片是由64x64像素构成的,而每个像素点由(R,G,B)三原色构成的,
# 所以要乘以3。在此之后,我们的训练和测试数据集是一个numpy数组,
# 【每列代表一个平坦的图像】 ,应该有m_train和m_test列。
train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T
# 将形状(a,b,c,d)的矩阵X平铺成形状(b * c * d,a)的矩阵X_flatten
print("训练集降维最后的维度: " + str(train_set_x_flatten.shape)) # (12288, 209) 12288行 209列(每一列上12288行 代表着一个图片)
print("训练集_标签的维数 : " + str(train_set_y.shape)) # (1, 209) 1行209列 ,训练有209张图片
print("测试集降维之后的维度: " + str(test_set_x_flatten.shape))
print("测试集_标签的维数 : " + str(test_set_y.shape))
# 标准化数据
train_set_x = train_set_x_flatten / 255 # 里面的数据每个除以255,像素值最大255
test_set_x = test_set_x_flatten / 255
- 第二步建立神经网络
建立神经网络的主要步骤是:
1.定义模型结构(例如输入特征的数量)
2.初始化模型的参数
3.循环:
计算当前损失(正向传播)
计算当前梯度(反向传播)
更新参数(梯度下降)
- 构建不同功能的函数:
sigmoid
函数作出预测
initialize_with_zeros
初始化数据w和b
propagate
成本函数这里的cost就是J,里面包括正向传播和反向传播
optimize
w和b迭代优化函数,梯度下降法更新参数
predict
预测函数,比较Sigam与0.5的大小,预测图片是1(>0.5猫)还是0(<0.5非猫)
model
整合以上函数,建立一个统一的模型。
def sigmoid(z):
s = 1 / (1 + np.exp(-z))
return s # 这里S就是我要构建的Sigma函数
# 初始化参数
def initialize_with_zeros(dim):
w = np.zeros(shape=(dim, 1))
b = 0
# 使用断言来确保我要的数据是正确的
assert (w.shape == (dim, 1)) # w的维度是(dim,1)
assert (isinstance(b, float) or isinstance(b, int)) # b的类型是float或者是int
return w, b
# 函数构造好了后,进行前向”和“后向”传播步骤来学习参数
# 计算成本函数及其渐变的函数propagate
def propagate(w, b, X, Y):
# W 权重,大小不等的数组(num_px*num_px*3 , 1 )
# b 偏差 X 矩阵类型(num_px*num_px*3 , 训练数量) Y(标签矢量 猫1 ,非猫0 ) ,维度(1 , 训练数量)
# dw db 只是损失梯度,与wb形状相同,后面用assert 断言函数判断是否相同
m = X.shape[1] # 数据量
# 正向传播
A = sigmoid(np.dot(w.T, X) + b)
# 计算成本
cost = (1 / m) * np.sum(-(Y * np.log(A) + (1 - Y) * np.log(1 - A)))
# 反向传播
dw = (1 / m) * np.dot(X, (A - Y).T)
db = (1 / m) * np.sum(A - Y)
assert (dw.shape == w.shape)
assert (db.dtype == float)
cost = np.squeeze(cost)
assert (cost.shape == ())
# 保存数据
grads = {
"dw": dw,
"db": db
}
return grads, cost
# w和b的优化
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost=False):
# num_iterations - 优化循环的迭代次数
# learning_rate - 梯度下降更新规则的学习率
# print_cost - 每100步打印一次损失值
# 返回:params - 包含权重w和偏差b的字典
# grads - 包含权重和偏差相对于成本函数的梯度的字典
# 成本 - 优化期间计算的所有成本列表,将用于绘制学习曲线。
costs = []
for i in range(num_iterations):
grads, cost = propagate(w, b, X, Y)
dw = grads["dw"]
db = grads["db"]
w = w - learning_rate * dw
b = b - learning_rate * db
# 记录成本
if i % 100 == 0:
costs.append(cost) # 数组,100倍数,记录下cost
# 打印成本数据
if (print_cost) and (i % 100 == 0):
print("迭代的次数: %i , 误差值: %f" % (i, cost))
params = {
"w": w,
"b": b}
grads = {
"dw": dw,
"db": db}
return params, grads, costs
def predict(w, b, X):
# 用logistic (w,b)预测标签是0还是1,
m = X.shape[1] # 图片的数量
Y_prediction = np.zeros((1, m))
w = w.reshape(X.shape[0], 1)
# 计预测猫在图片中出现的概率
A = sigmoid(np.dot(w.T, X) + b)
for i in range(A.shape[1]):
# 将概率a [0,i]转换为实际预测p [0,i]
Y_prediction[0, i] = 1 if A[0, i] > 0.5 else 0
# 使用断言
assert (Y_prediction.shape == (1, m))
return Y_prediction
# 已经做完所有的工作,将其合并一下
def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):
w, b = initialize_with_zeros(X_train.shape[0])
parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost)
# 从字典“参数”中检索参数w和b
w, b = parameters["w"], parameters["b"]
# 预测测试/训练集的例子
Y_prediction_test = predict(w, b, X_test)
Y_prediction_train = predict(w, b, X_train)
# 打印训练后的准确性
print("训练集准确性:", format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100), "%")
print("测试集准确性:", format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100), "%")
d = {
"costs": costs,
"Y_prediction_test": Y_prediction_test,
"Y_prediciton_train": Y_prediction_train,
"w": w,
"b": b,
"learning_rate": learning_rate,
"num_iterations": num_iterations}
return d
在测试中我们可以比较一下我们模型的学习曲线和几种学习速率的选择。也可以尝试使用不同于我们初始化的learning_rates变量包含的三个值,并看一下会发生什么。
learning_rate = [0.01, 0.001, 0.0001]
models = {}
for i in learning_rate :
print("learning rate is "+str(i))
models[str(i)] = model(train_set_x,train_set_y,test_set_x,test_set_y, num_iterations=2000, learning_rate=i, print_cost=False)
print('\n' + "-------------------------------------------------------" + '\n')
for i in learning_rate :
plt.plot(np.squeeze(models[str(i)]["costs"]), label=str(models[str(i)]["learning_rate"]))
plt.ylabel('cost')
plt.xlabel('iterations')
legend = plt.legend(loc='upper center', shadow=True)
frame = legend.get_frame()
frame.set_facecolor('0.90')
plt.show()
图像为
不同的学习速率,造成不同的影响,速率过大,容易造成过拟合,过小,要迭代很多次才成功。
可以看到
learning rate is: 0.01
训练集准确性: 99.52153110047847 %
测试集准确性: 68.0 %
-------------------------------------------------------
learning rate is: 0.001
训练集准确性: 88.99521531100478 %
测试集准确性: 64.0 %
-------------------------------------------------------
learning rate is: 0.0001
训练集准确性: 68.42105263157895 %
测试集准确性: 36.0 %
-------------------------------------------------------
第三周 浅层神经网络的学习
下图是一个双层神经网路图
a[1]表示第一层,a[2]第二层。在之前的w和b优化中,我们只是一层的优化,这里还分了w[1],w[2]和b[1],b[2],注意维数不同。
- 下图左侧为前一周的单个网络,这里右侧每一个都是重复一次,采用下角标进行区分,上角标代表层数。
矩阵化处理
- 目前用的激活函数(预测)都是
sigmoid
函数,还有一些函数效果会更好,比如双曲正切函数tanh
,此函数几乎在任何场合比sigmoid
函数更好,但是他们存在一个共同的缺点,当z很大时候,梯度小,学习效率就会降低。
还存有一个Relu
函数,公式为a=max(0,z)
- 选取激活函数有一些小经验:如果输出为0或1,在做2元分类时候,那么可以选择
sigmoid
函数作为激活函数,其他层都用ReLU
函数,修正线性单元,已经是激活函数默认选择。还有一个函数为leaky ReLU
,此函数在z<0时候是一个缓慢下降的,比ReLU
还好用,但是一般用的很少。
带有一个隐藏层的平面数据分类
- 本文笔记代码参考何宽此篇文章所写,点击即可进去
在这个部分所用的代码,中间加入了一个隐藏层
- 所使用的数据为
planar_utils
,以及测试用例testCases
后面也会附上 - 绘制散点图,入下图:
'''X:一个numpy的矩阵,包含了这些数据点的数值
Y:一个numpy的向量,对应着的是X的标签【0 | 1】(红色:0 , 蓝色 :1)'''
X, Y = load_planar_dataset()
plt.scatter(X[0, :], X[1, :], c=np.squeeze(Y), s=40, cmap=plt.cm.Spectral)
# plt.cm.Spectral 给lable 0/1 两个标签不同的颜色
- 用上一个逻辑回归的效果:
# 逻辑回归分类效果!
clf = sklearn.linear_model.LogisticRegressionCV()
clf.fit(X.T, Y.T)
plot_decision_boundary(lambda x: clf.predict(x), X, Y) # 绘制决策边界
# plot_decision_boundary(lambda x: predict(parameters, x.T), X, np.squeeze(Y))#修改
# plt.title("Decision Boundary for hidden layer size " + str(4))
plt.title("Logistic Regression") # 图标题
LR_predictions = clf.predict(X.T) # 预测结果
print("逻辑回归的准确性: %d " % float((np.dot(Y, LR_predictions) +
np.dot(1 - Y, 1 - LR_predictions)) / float(Y.size) * 100) +
"% " + "(正确标记的数据点所占的百分比)")
plt.show()
逻辑回归的准确性: 47 % (正确标记的数据点所占的百分比)
- 可以看到效果不佳,准确性只有47%的原因是数据集不是线性可分的。
接下来进行构造
反向传播:
成本计算为:
在这里构造与上面的构造大致类似,只是多了个层数,维数变多:
layer_sizes
定义神经网络结构,输入层,隐藏层,输出层各自的数量。
initialize_parameters
初始化模型参数,随机值初始化权重矩阵
forward_propagation
前向传播,Z[1],A[1],Z[2],A[2]
compute_cost
成本函数J
backward_propagation
反向传播函数
update_parameters
更新函数
predict
预测函数
nn_model
整合全部函数
下面是具体代码
# 搭建神经网络
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):
"""
parameters - 包含参数的字典:
W1 - 权重矩阵,维度为(n_h,n_x)
b1 - 偏向量,维度为(n_h,1)
W2 - 权重矩阵,维度为(n_y,n_h)
b2 - 偏向量,维度为(n_y,1)
"""
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
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 compute_cost(A2, Y, parameters):
# A2 - 使用sigmoid()函数计算的第二次激活后的数值
# Y - "True"标签向量,维度为(1,数量)
# parameters - 一个包含W1,B1,W2和B2的字典类型的变量
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)) # 去掉冗余的位数 [[[ 10 , 2 , 3 ]]] ----> [10,2,3]
assert (isinstance(cost, float))
return cost
# 反向传播
def backward_propagation(parameters, cache, X, Y):
# parameters - 包含我们的参数的一个字典类型的变量。
# cache - 包含“Z1”,“A1”,“Z2”和“A2”的字典类型的变量。
# X - 输入数据,维度为(2,数量)
# Y - “True”标签,维度为(1,数量)
# grads - 包含W和b的导数一个字典类型的变量。
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}
return grads
def update_parameters(parameters, grads, learning_rate=1.2):
# 使用上面给出的梯度下降更新规则更新参数
# parameters - 包含参数的字典类型的变量。
# grads - 包含导数值的字典类型的变量。
# learning_rate - 学习速率
# parameters - 包含更新参数的字典类型的变量。
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
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)
grads = backward_propagation(parameters, cache, X, Y)
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):
# 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)
- 测试:
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) + '%')
第 0 次循环,成本为:0.6930480201239823
第 1000 次循环,成本为:0.3098018601352803
第 2000 次循环,成本为:0.2924326333792646
第 3000 次循环,成本为:0.2833492852647411
第 4000 次循环,成本为:0.27678077562979253
第 5000 次循环,成本为:0.2634715508859307
第 6000 次循环,成本为:0.24204413129940758
第 7000 次循环,成本为:0.23552486626608762
第 8000 次循环,成本为:0.23140964509854278
第 9000 次循环,成本为:0.22846408048352362
准确率: 90%