编程能力很差,用博客记录一下作业的流程。然后希望可以把流程理顺。
逻辑回归与神经网络思维
欢迎参加您的第一次(必修)编程作业!您将构建一个逻辑回归分类器来识别猫。这个作业将指导您如何使用神经网络的思维来完成这个任务,同时也会提高您对深度学习的直觉。
指示:
- 不要使用循环(for/while),除非指令明确要求这样做。
- 您将学习如何:
- 构建学习算法的一般架构,包括:
- 初始化参数
- 计算成本函数及其梯度
- 使用优化算法(梯度下降)
- 将上述三种功能整合到一个主模型函数中,并按正确的顺序执行。
- 构建学习算法的一般架构,包括:
这个是一个小工具用来处理数据集
import numpy as np
import h5py
def load_dataset():
train_dataset = h5py.File('datasets/train_catvnoncat.h5', "r")# 以只读方式打开训练集数据
train_set_x_orig = np.array(train_dataset["train_set_x"][:]) # your train set features
train_set_y_orig = np.array(train_dataset["train_set_y"][:]) # your train set labels
test_dataset = h5py.File('datasets/test_catvnoncat.h5', "r")
test_set_x_orig = np.array(test_dataset["test_set_x"][:]) # 获取数据
test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # 获取标签
classes = np.array(test_dataset["list_classes"][:]) # the list of classes
train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))# reshape输出,使维度不会出现错误
test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))
return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes
初始化参数
import numpy as np
import matplotlib.pyplot as plt
import h5py
import scipy
from PIL import Image
from scipy import ndimage
from lr_utils import load_dataset
# Loading the data (cat/non-cat)
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()
我们给训练和测试图像数据集的名称后面加上了"_orig",是因为我们打算对它们进行预处理。预处理之后,我们将得到train_set_x
和test_set_x
(标签train_set_y
和test_set_y
不需要任何预处理)。
你的train_set_x_orig
和test_set_x_orig
的每一行都是一个数组,代表一张图像。你可以通过运行以下代码来可视化一个示例。你也可以随意更改索引值并重新运行,以查看其他图像。
# Example of a picture
index = 23
plt.imshow(test_set_x_orig[index])
print ("y = " + str(test_set_y[:, index]) + ", it's a '" + classes[np.squeeze(test_set_y[:, index])].decode("utf-8") + "' picture.")
plt.show()
运行效果如下:
查看一下测试集数据
print(test_set_x_orig[:])
print(test_set_x_orig.shape)
运行结果:
在深度学习中,许多软件错误源于矩阵/向量的维度不匹配。如果你能确保矩阵/向量的维度正确,你将能够消除许多错误。
练习:找出以下值:
- m_train(训练样本的数量)
- m_test(测试样本的数量)
- num_px(训练图像的高度=宽度) 记住,train_set_x_orig是一个形状为(m_train, num_px, num_px, 3)的numpy数组。例如,你可以通过写作train_set_x_orig.shape[0]来访问m_train。
通过上面的代码可以知道test数量是50,宽等于高就是64,通道是3,用来表示颜色。
m_train = train_set_x_orig.shape[0]
m_test = test_set_x_orig.shape[0]
num_px = train_set_x_orig.shape[1]
为了方便,你现在应该将形状为(num_px, num_px, 3)的图像重塑为一个形状为(num_px × num_px × 3, 1)的NumPy数组。这样,我们的训练(和测试)数据集就是一个NumPy数组,其中每一列代表一个展平的图像。应该有m_train(分别m_test)列。
练习:将训练和测试数据集重塑,以便将尺寸为(num_px, num_px, 3)的图像展平为单个向量,形状为(num_px × num_px × 3, 1)。
当你想要将形状为(a, b, c, d)的矩阵X展平为形状为(b * c * d, a)的矩阵X_flatten时,可以使用以下技巧:
X_flatten = X.reshape(X.shape[0], -1).T # X.T是X的转置
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
为了表示彩色图像,必须为每个像素指定红色、绿色和蓝色通道(RGB),因此像素值实际上是一个包含三个数字的向量,每个数字的范围从0到255。
在机器学习中,一种常见的数据预处理步骤是将数据集居中并标准化,这意味着从整个NumPy数组的均值中减去每个样本,并然后除以整个NumPy数组的标准差。但对于图像数据集来说,更简单、更方便,并且几乎同样有效的方法是将数据集中的每一行除以255(像素通道的最大值)。
让我们标准化我们的数据集。
标准化图像数据集的步骤通常如下:
-
计算均值和标准差:首先计算整个数据集中所有像素值的均值和标准差。这可以通过NumPy的
mean
和std
函数来完成。 -
居中数据:从每个像素值中减去均值,使得数据集的像素值围绕0分布。
-
标准化:将每个像素值除以标准差,这样数据集的像素值将具有单位方差。
-
归一化:将每个像素值除以255,这是一种简单的归一化方法,可以减少数值的规模,使得所有像素值的范围在0到1之间。
例如,如果你有一个图像数据集X
,你可以使用以下代码来进行归一化:
train_set_x = train_set_x_flatten/255.
test_set_x = test_set_x_flatten/255.
3 - 学习算法的通用架构 是时候设计一个简单的算法来区分猫的图片和非猫的图片了。
你将使用神经网络的思维来构建一个逻辑回归。下面的图表解释了为什么逻辑回归实际上是一个非常简单的神经网络!
关键步骤:在这个练习中,你将执行以下步骤:
- 初始化模型的参数
- 通过最小化成本来学习模型的参数
- 使用学到的参数进行预测(在测试集上)
- 分析结果并得出结论
4 - 构建我们算法的部分 构建神经网络的主要步骤包括:
- 定义模型结构(例如输入特征的数量)
- 初始化模型的参数
- 循环:
- 计算当前损失(前向传播)
- 计算当前梯度(反向传播)
- 更新参数(梯度下降)
- 你通常会分别构建1-3步,并将它们集成到一个我们称之为
model()
的函数中。
4.1 - 辅助函数 练习:使用你在“Python基础”中的代码,实现sigmoid()
函数。如上文所述,你需要计算以下公式来进行预测:
𝜎(𝑧)=11+𝑒−𝑧σ(z)=1+e−z1
使用np.exp()
来计算。
下面是sigmoid
函数的实现代码示例
def sigmoid(z):
s = 1 / (1 + np.exp(-z))
return s
4.2 - 初始化参数 练习:在下面的单元格中实现参数初始化。你必须将w
初始化为一个零向量。如果你不知道要使用哪个NumPy函数,请查阅NumPy库中np.zeros()
的文档。
def initialize_with_zeros(dim):
'''
:param dim: 输入维度
:return: 初始化后的w,b
'''
w = np.zeros((dim,1))
b = 0
# 使用断言保证维度正确
assert(w.shape == (dim,1))
assert(isinstance(b,float) or isinstance(b,int))
return w,b
4.3 - 前向传播和反向传播 现在你的参数已经初始化了,你可以进行学习参数的“前向”和“后向”传播步骤。
练习:实现一个propagate()
函数,计算成本函数及其梯度。
提示:
前向传播:
前向传播是神经网络中计算输出的过程,它涉及以下步骤:
- 输入层:将输入数据
X
传递给网络。 - 隐藏层:如果有,使用激活函数(如sigmoid函数)和权重
W
以及偏置b
来计算隐藏层的激活值。 - 输出层:使用隐藏层的激活值(如果有多个隐藏层,则使用最后一个隐藏层的激活值)来计算最终的输出值。
数学上,如果我们有一个简单的逻辑回归模型,前向传播可以表示为: 𝑍=𝑊×𝑋+𝑏Z=W×X+b 𝐴=𝜎(𝑍)A=σ(Z) 其中:
W
是权重矩阵。X
是输入数据。b
是偏置项。Z
是线性组合的结果。A
是激活函数的输出,例如sigmoid函数。
在更复杂的网络中,这个过程会在多个层之间重复进行。
为了实现propagate()
函数,你需要编写代码来执行以下任务:
- 计算给定输入
X
和真实标签Y
的损失函数。 - 计算损失函数相对于网络参数(权重和偏置)的梯度。
这通常涉及到计算预测的输出,然后使用链式法则来反向传播误差,从而得到每个参数的梯度。这些梯度随后可以用于通过梯度下降或其他优化算法更新网络的参数。
def propagate(w,b,X,Y):
m = X.shape[1]
z = np.dot(w.T,X) + b
A = sigmoid(z)
cost = -1 / m * (np.dot(np.log(A),Y.T) + np.dot(np.log(1-A),(1-Y).T))
dw = 1 / m * (np.dot(X,(A-Y).T))
db = np.average(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
你已经初始化了你的参数。 你也能够计算成本函数及其梯度。 现在,你想要使用梯度下降来更新参数。 练习:写下优化函数。目标是通过最小化成本函数来学习 𝜃θ。 对于一个参数 𝜃θ,更新规则是 𝜃=𝜃−𝛼⋅𝑑_𝑡ℎ𝑒𝑡𝑎θ=θ−α⋅d_theta,其中 𝛼α 是学习率。
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):
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)
if print_cost and i % 100 == 0:
print("Cost after iteration %i: %f" %(i,cost))
params = {"w": w,
"b":b}
grads = {"dw":dw,
"db":db}
return params, grads, costs
之前的函数将输出学习到的权重 w
和偏置 b
。我们可以使用 w
和 b
来预测数据集 X
的标签。实现 predict()
函数。计算预测有两个步骤:
-
计算激活值:首先,你需要使用学习到的参数
w
和b
来计算输入数据X
的激活值。这通常是通过一个线性方程z = w * X + b
来完成的,然后通过一个激活函数(例如 sigmoid 函数)来转换这些线性值。 -
阈值化:将激活值转换为二进制预测。如果激活值小于或等于0.5,将其转换为0;如果激活值大于0.5,将其转换为1。预测结果存储在一个向量
Y_prediction
中。你可以使用 if/else 语句在一个 for 循环中进行转换,也可以使用向量化的方式来实现这一点。
def predict(w, b, X):
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)
Y_prediction = np.where(A <= 0.5,0,1)
assert(Y_prediction.shape ==(1,m))
return Y_prediction
5 - 将所有函数合并为一个模型 现在你将看到如何通过将前几部分实现的所有构建块(函数)以正确的顺序组合在一起来构建整体模型结构。
练习:实现模型函数。使用以下符号表示:
Y_prediction
用于在测试集上的预测Y_prediction_train
用于在训练集上的预测w
,costs
,grads
用于optimize()
函数的输出
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 = parameters['w']
b = 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_prediction_train": Y_prediction_train,
"w": w,
"b": b,
"learning_rate": learning_rate,
"num_iterations": num_iterations}
return d
d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 1000, learning_rate = 0.005, print_cost = True)
costs = np.squeeze(d['costs'])
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(d["learning_rate"]))
plt.show()