这段代码是一个简单逻辑回归模型,用于识别图片中的猫。主要步骤包括:
1. 导入所需库,当构建识别图片是否有猫的神经网络模型时,我们还需要导入其他的库来辅助处理数据和评估模型的准确度,如numpy、matplotlib等。
2. 准备数据集:准备数据集是进行机器学习和深度学习任务中至关重要的一步。首先需要收集包含有猫和不包含猫的图片数据集。可以选择使用开源数据集,例如COCO、ImageNet中的部分数据集或者Kaggle上的猫狗分类数据集等。另外也可以自行收集图片数据,确保数据集中有两个明确定义的类别:包含猫和不包含猫的图片。在收集或选择数据集时需要注意数据的多样性和均衡性,以确保模型在训练和测试时能够得到充分的代表性。
3. 数据预处理:在准备数据集的过程中,还需要对数据进行一些预处理工作,包括去除重复图片、调整图片尺寸、统一格式等,以便后续的模型训练和评估。同时,为了避免过拟合和提高模型的泛化能力,还可以考虑使用数据增强技术,如随机裁剪、翻转、旋转等,增加数据集的多样性。
4. 构建CNN模型:搭建深度学习模型,包括卷积层、池化层、全连接层等。构建卷积神经网络(CNN)模型是一项重要的深度学习任务,其中需要设计卷积层、池化层和全连接层等核心组件。卷积层负责提取输入数据的特征图,通过滤波器进行局部特征提取;池化层则对特征图进行降维操作,同时保持重要信息;全连接层将池化后的特征图映射到最终的输出空间,进行分类或回归预测。在构建CNN模型时,需谨慎选择层的参数设置和结构连接,以获得最佳的性能和泛化能力。
5. 训练模型:在训练深度学习模型时,常见的做法是将数据集划分为训练集和测试集。训练集用于模型参数的更新和优化,以使模型能够准确地拟合训练数据。而测试集则用于验证模型的泛化能力,通过在未见过的数据上进行评估,从而判断模型在实际应用中的性能表现。合理的训练集和测试集划分可以帮助评估模型的过拟合情况,并对模型进行调优,以取得更好的预测效果。
6. 评估模型:使用测试集对模型进行评估,看模型在识别图片中是否有猫的准确度。评估模型的性能是深度学习中一个关键的步骤,尤其是在图像识别任务中。对于识别图片中是否有猫的任务,我们可以使用测试集对模型进行评估。一种常用的评估指标是准确度(accuracy),即模型正确预测出有猫的样本在测试集中所占的比例。通过计算模型在测试集上的准确度,我们能够得到一个直观的衡量模型性能的指标。除了准确度,还可以使用其他指标如精确度、召回率和F1值等来评估模型的性能。为了更全面地评估模型的性能,我们可以计算混淆矩阵,包括真阳性、假阳性、真阴性和假阴性。基于混淆矩阵,我们可以计算出精确度、召回率和F1值。精确度表示模型在预测为有猫的样本中的正确率,召回率表示模型能够正确预测出有猫的样本的比例,F1值是精确度和召回率的调和平均。除了单一指标的评估,我们还可以可视化模型的预测结果,对比模型的误分类样本和正确分类样本,从而更深入地分析模型的性能和改进方向。通过综合考虑准确度和其他评估指标,以及对模型预测结果的可视化分析,我们能够更全面地评估模型对于识别图片中是否有猫的效果。
详细程序及注释如下:
# --------------欢迎关注Archie_IT-------
# --以下实现搭建一个识别图片中“猫”的神经网络训练模型----代码注释详细--
import numpy as np
import matplotlib.pyplot as plt # plt用于显示图片
import h5py
from lr_utils import load_dataset # 在lr_utils.py文件导入load_dataset数据的简单功能的库
# 将这些数据加载到主程序里面
train_set_x_orig , train_set_y_orig , test_set_x_orig , test_set_y_orig , classes = load_dataset()
'''
train_set_x_orig ---保存的是训练集里面的图像数据(本训练集有209张64x64的图像)
train_set_y_orig ---保存的是训练集的图像对应的分类值(0表示不是猫,1表示是猫) 标签值
test_set_x_orig---保存的是测试集里面的图像数据(本训练集有50张64x64的图像)
test_set_y_orig--- 保存的是测试集的图像对应的分类值(0表示不是猫,1表示是猫) 标签值
classes = load_dataset()---保存的是以bytes类型保存的两个字符串数据,数据为:[b’non-cat’, b’cat’]
'''
index = 25
plt.imshow(train_set_x_orig[index]) # 显示训练集里面的第25个图片,索引25
plt.show()
'''
打印出当前的训练标签值
使用np.squeeze的目的是压缩维度,【未压缩】train_set_y[:,index]的值为[1] , 【压缩后】np.squeeze(train_set_y[:,index])的值为1
print("【使用np.squeeze:" + str(np.squeeze(train_set_y[:,index])) + ",不使用np.squeeze: " + str(train_set_y[:,index]) + "】")
只有压缩后的值才能进行解码操作
'''
print("y=" + str(train_set_y_orig[:,index]) + ", it's a " + classes[np.squeeze(train_set_y_orig[:,index])].decode("utf-8") + " picture")
# train_set_x_orig.shape # (209, 64, 64, 3) 本训练集有209张64*64的图片,图像存储为三维数组
# train_set_y_orig.shape # (1, 209)
'''
查看一下加载的图像数据集具体情况
1.num_train ---训练集里图片的数量
2.num_test ---测试集里图片的数量
3.num_px ---训练/测试集里面图片的宽度和高度都是64*64px
4.每张图片的大小
5.训练集_图片的维数
6.训练集_标签的维数
7.测试集_图片的维数
8.测试集_标签的维数
train_set_x_orig 是一个维度为(num_train,num_px,num_px,3)的数组。
'''
num_train = train_set_y_orig.shape[1] # 训练集里图片的数量
num_test = test_set_y_orig.shape[1] # 测试集里图片的数量
num_px = train_set_x_orig.shape[1] # 训练/测试集里面图片的宽度和高度都是64*64px
# 查看加载的具体情况
print("训练集的数量:num_train = " + str(num_train))
print("测试集的数量:num_test = " + str(num_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_orig.shape))
print("测试集_图片的维数:"+str(test_set_x_orig.shape))
print("测试集_标签的维数:"+str(test_set_y_orig.shape))
'''
训练集和测试集降维
为了方便,将每张图片的大小(64,64,3)重新构造为(64*64*3,1)的数组,每个像素点由三原色构成所以没张图片像素64*64*3。
在此之后,训练数据集和测试数据集是一个numpy数组,每列代表一个图像,训练数据集应该有12288(特征数量)行和209(样本数量)列。
train_set_x_orig.shape[0]为209个图片,列的值输入为-1让机器帮忙算出是12288,然后将209与12288转置互换位置
'''
train_set_x_faltten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
test_set_x_faltten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T
print("训练集_降维后的维度:"+str(train_set_x_faltten.shape))
print("训练集_标签的维度:"+str(train_set_y_orig.shape))
print("测试集_降维后的维度:"+str(test_set_x_faltten.shape))
print("测试集_标签的维度:"+str(test_set_y_orig.shape))
'''
1.标准化数据集:机器学习中一个常见的预处理步骤是对数据集进行居中和标准化,这意味着可以减去每个示例中整个numpy数组的平均值,然后将每个示例除以
整个nump数组的标准偏差。
2.像素值是0-255,在rgb中不存在大于255,所以可以直接将数据集除以255,让标准的数据位于【0-1】之间
'''
# 标准化数据集
train_set_x = train_set_x_faltten / 255
test_set_x = test_set_x_faltten / 255
'''
以上加载的数据处理完毕
开始构建神经网络
建立神经网络的主要步骤是:
1.定义模型结构(例如输入特征的数量)
2.初始化模型的参数
3.循环:
计算当前损失(正向传播)
计算当前梯度(反向传播)
更新参数(梯度下降)
'''
'''
一.构建sigmod,以使用其计算来做出预测
参数z可以是任何大小的标量或numpy数组
返回值s是sigmoid(z)
'''
def sigmoid(z):
s = 1 / (1+np.exp(-z))
return s
# 测试sigmoid()
print("--------------测试sigmoid--------------")
print("sigmoid(0) = " + str(sigmoid(0)))
print("sigmoid(9.2) = " + str(sigmoid(9.2)))
'''
二.初试化参数w和b,构建初始化参数的函数
此函数为w创建一个维度为(dim,1)的0向量,并将b初始化为0。
参数:dim - 我们想要的w矢量的大小(或者这种情况下的参数数量)
返回: w - 维度为(dim,1)的初始化向量。
b - 初始化的标量(对应于偏差)
'''
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()
参数:
w - 权重,大小不等的数组(num_px * num_px * 3,1)
b - 偏差,一个标量
X - 矩阵类型为(num_px * num_px * 3,训练数量)
Y - 真正的“标签”矢量(如果非猫则为0,如果是猫则为1),矩阵维度为(1,训练数据数量)
返回:
cost- 逻辑回归的负对数似然成本
dw - 相对于w的损失梯度,因此与w相同的形状
db - 相对于b的损失梯度,因此与b的形状相同
'''
def propagate(w, b, X, Y):
m = X.shape[1]
# 正向传播
A = sigmoid(np.dot(w.T, X) + b) # 计算激活值--- y^
cost = (- 1 / m) * np.sum(Y*np.log(A) + (1 - Y) * (np.log(1 - A))) # 计算成本J
# 反向传播
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 == ())
# 创建一个字典,把dw和db保存起来
grads = {
"dw": dw,
"db": db
}
return (grads , cost)
# 测试propagate
print("----------测试propagate----------")
# 初始化一些参数
w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1, 2], [3, 4]]), np.array([[1, 0]])
grads, cost = propagate(w, b, X, Y)
print("dw = " + str(grads["dw"]))
print("db = " + str(grads["db"]))
print("cost = " + str(cost))
print("grads = " + str(grads))
'''
四.梯度下降更新参数,optimize()此函数通过运行梯度下降算法来优化w和b
目标是通过最小化成本函数J来学习w和b。对于参数h,更新规则是h=h-αdh,其中α是学习率
参数:
w - 权重,大小不等的数组(num_px * num_px * 3,1)
b - 偏差,一个标量
X - 维度为(num_px * num_px * 3,训练数据的数量)的数组。
Y - 真正的“标签”矢量(如果非猫则为0,如果是猫则为1),矩阵维度为(1,训练数据的数量)
num_iterations - 优化循环的迭代次数
learning_rate - 梯度下降更新规则的学习率
print_cost - 每100步打印一次损失值
返回:
params - 包含权重w和偏差b的字典
grads - 包含权重和偏差相对于成本函数的梯度的字典
成本 - 优化期间计算的所有成本列表,将用于绘制学习曲线。
提示:
我们需要写下两个步骤并遍历它们:
1)计算当前参数的成本和梯度,使用propagate()。
2)使用w和b的梯度下降法则更新参数。
'''
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost=True):
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("迭代的次数: %i , 误差值: %f" % (i, cost))
params = {
"w": w,
"b": b}
grads = {
"dw": dw,
"db": db}
return (params, grads, costs)
#测试optimize
print("====================测试optimize====================")
w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
params , grads , costs = optimize(w , b , X , Y , num_iterations=100 , learning_rate = 0.009 , print_cost = True)
print ("w = " + str(params["w"]))
print ("b = " + str(params["b"]))
print ("dw = " + str(grads["dw"]))
print ("db = " + str(grads["db"]))
'''
optimize函数会输出已学习的w和b的值,可以用w和b来预测数据集X的标签
五.实现预测函数predict(),计算预测的步骤有两步:
1.计算y^
2.将a的值变为0(如果激活值<= 0.5)或者为1(如果激活值> 0.5),然后将预测值存储在向量Y_prediction中。
使用学习逻辑回归参数logistic (w,b)预测标签是0还是1,
参数:
w - 权重,大小不等的数组(num_px * num_px * 3,1)
b - 偏差,一个标量
X - 维度为(num_px * num_px * 3,训练数据的数量)的数据
返回:
Y_prediction - 包含X中所有图片的所有预测【0 | 1】的一个numpy数组(向量)
'''
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)
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
#测试predict
print("====================测试predict====================")
w, b, X, Y = np.array([[1], [2]]), 2, np.array([[1,2], [3,4]]), np.array([[1, 0]])
print("predictions = " + str(predict(w, b, X)))
'''
就目前而言,我们基本上把所有的东西都做完了,现在我们要把这些函数统统整合到一个model()函数中,
届时只需要调用一个model()就基本上完成所有的事了。
'''
def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=True):
"""
通过调用之前实现的函数来构建逻辑回归模型
参数:
X_train - numpy的数组,维度为(num_px * num_px * 3,m_train)的训练集
Y_train - numpy的数组,维度为(1,m_train)(矢量)的训练标签集
X_test - numpy的数组,维度为(num_px * num_px * 3,m_test)的测试集
Y_test - numpy的数组,维度为(1,m_test)的(向量)的测试标签集
num_iterations - 表示用于优化参数的迭代次数的超参数
learning_rate - 表示optimize()更新规则中使用的学习速率的超参数
print_cost - 设置为true以每100次迭代打印成本
返回:
d - 包含有关模型信息的字典。
"""
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
print("====================测试model====================")
#这里加载的是真实的数据,请参见上面的代码部分。
d = model(train_set_x, train_set_y_orig, test_set_x, test_set_y_orig, num_iterations = 2000, 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()
'''
进一步分析一下,并研究学习率alpha的可能选择。
为了让渐变下降起作用,我们必须明智地选择学习速率。学习率 α \alphaα 决定了我们更新参数的速度。
如果学习率过高,我们可能会“超过”最优值。同样,如果它太小,我们将需要太多迭代才能收敛到最佳值。
这就是为什么使用良好调整的学习率至关重要的原因。
可以比较一下我们模型的学习曲线和几种学习速率的选择。也可以尝试使用不同于我们初始化的learning_rates变量包含的三个值,并看一下会发生什么。
'''
learning_rates = [0.005, 0.01, 0.001, 0.0001]
models = {}
for i in learning_rates:
print ("learning rate is: " + str(i))
print("num_iterations=2000")
models[str(i)] = model(train_set_x, train_set_y_orig, test_set_x, test_set_y_orig, num_iterations = 2000, learning_rate = i, print_cost = True)
print ('\n' + "-------------------------------------------------------" + '\n')
for i in learning_rates:
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()