前言
使用框架搭建神经网络很简单,但是不用框架从头搭建一个神经网络更能加深理解。
本文使用numpy实现了一个四层的DNN来对图片进行二分类:来判断图片中是否有猫。
项目源自吴恩达老师在Coursera开设的深度学习课程的课后作业,代码和原课后作业不完全相同,所有关键的地方我都写了注释。建议先大体看一下都有哪些部分,然后从训练模型部分开始看起。我认为,代码写的时候要先写框架,再写具体函数实现,看代码当然也是同理。
源码:github
构建神经网络的大体步骤
1 . 训练集测试集搞好,模型框架定好(几层网络,每层几个神经元)
2 . 初始化权重,定超参数
3 . 训练模型(重头戏):
循环(需要定义迭代次数):
a.前向传播
b.计算代价函数
c.后向传播
d.更新参数(使用后向传播中存下来的参数)
4 . 使用训练过的参数去预测结果
代码讲解
第一步先导入一堆需要用到的包。
import numpy as np
import h5py
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['figure.figsize'] = (5.0, 4.0) # 设定图片的默认尺寸
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
%load_ext autoreload
%autoreload 2
np.random.seed(1)
下面定义好要用的一些函数:
前向传播、后向传播的sigmoid和relu。最后定义了加载数据的函数
def sigmoid(Z):
"""
使用numpy实现sigmoid函数
Arguments:
Z -- 任何尺寸的numpy array
Returns:
A -- 输出sigmoid(z), 形状和Z一样
cache -- 就是Z,在反向传播中会用到
"""
A = 1/(1+np.exp(-Z))
cache = Z
return A, cache
def relu(Z):
"""
使用numpy实现relu函数
Arguments:
Z -- 任何尺寸的numpy array
Returns:
A -- 输出relu(z), 形状和Z一样
cache -- 就是Z,在反向传播中会用到
"""
A = np.maximum(0,Z)
assert(A.shape == Z.shape)
cache = Z
return A, cache
def relu_backward(dA, cache):
"""
实现了relu单元的反向传播
Arguments:
dA -- 激活函数的梯度
cache -- 之前定义的relu函数中的返回值,前向传播之前的Z
Returns:
dZ -- 损失函数对Z的梯度
"""
Z = cache
dZ = np.array(dA, copy=True) # relu导数为1(输入大于0),所以直接直接复制一份dA即可
dZ[Z <= 0] = 0 # 当输入小于0时,relu导数为0,所以dZ中小于0的数变为0
assert (dZ.shape == Z.shape)
return dZ
def sigmoid_backward(dA, cache):
"""
实现了sigmoid单元的反向传播
Arguments:
dA -- 激活函数的梯度
cache -- 之前定义的sigmoid函数中的返回值,前向传播之前的Z
Returns:
dZ -- 损失函数对Z的梯度
"""
Z = cache
s = 1/(1+np.exp(-Z))
dZ = dA * s * (1-s) # dA乘sigmoid导数
assert (dZ.shape == Z.shape)
return dZ
def load_data():
"""
读取数据
"""
train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")
train_set_x_orig = np.array(train_dataset["train_set_x"]) # 训练样本 shape:(209, 64, 64, 3)
train_set_y_orig = np.array(train_dataset["train_set_y"]) # 训练样本标签 shape:(1, 209)
test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
test_set_x_orig = np.array(test_dataset["test_set_x"]) # 测试样本 shape:(50, 64, 64, 3)
test_set_y_orig = np.array(test_dataset["test_set_y"]) # 测试样本标签 shape:(1, 50)
classes = np.array(test_dataset["list_classes"][:]) # 标签类别(一共两类:是猫、不是猫)
train_set_y_orig = train_set_y_orig.reshape((1, -1)) # 确保标签是一行数据 下同
test_set_y_orig = test_set_y_orig.reshape((1, -1))
return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes
使用定义好的加载数据函数load_data()
将数据加载进来,然后看一看你的数据,先熟悉熟悉数据是什么样的嘛。
# 把数据弄下来
train_x_orig, train_y, test_x_orig, test_y, classes = load_data()
# 瞅一瞅你的数据
m_train = train_x_orig.shape[0]
num_px = train_x_orig.shape[1]
m_test