赞
踩
为了更好的掌握吴恩达深度学习——神经网络基础中的理论知识。跟我一起来看下如何用逻辑回归来实现图像识别算法,识别一个图像中有没有含有猫(实际上就是二分类问题)。
关于本文代码中的公式推导可见吴恩达深度学习——神经网络基础。
这是吴恩达深度学习第一节课的作业,如果你也在学习吴恩达深度学习教程,并且未做作业的话,建议你关闭该网页,根据作业指导自己实现代码先。
首先来看下我们的数据集。
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"][:]) # your test set features
test_set_y_orig = np.array(test_dataset["test_set_y"][:]) # your test set labels
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]))
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
上面是加载数据集的代码,数据集下载
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()
# Example of a picture
index = 2
plt.imshow(train_set_x_orig[index])
print(train_set_x_orig.shape)
print ("y = " + str(train_set_y[:, index]) + ", it's a '" + classes[np.squeeze(train_set_y[:, index])].decode("utf-8") + "' picture.")
print(train_set_y.shape) #(1, 209)
我们看下数据集的样子,从输出可以看到,有209个
64
×
64
×
3
64\times 64 \times3
64×64×3像素(rgb)的图片。
可以看到数据集是一个多维数组,我们先把它们转换成(特征数,样本数)这样维度的数组。
train_set_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0],-1).T# train_set_x_orig.shape[0]就是样本数,-1代表让python自己算,最后进行转置,就得到了我们想要的结果
test_set_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0],-1).T
print ("train_set_x_flatten shape: " + str(train_set_x_flatten.shape))
print ("train_set_y shape: " + str(train_set_y.shape))
print ("test_set_x_flatten shape: " + str(test_set_x_flatten.shape))
print ("test_set_y shape: " + str(test_set_y.shape))
输出为:
train_set_x_flatten shape: (12288, 209)
train_set_y shape: (1, 209)
test_set_x_flatten shape: (12288, 50)
test_set_y shape: (1, 50)
通常对于图像数据需要进行归一化处理,这里只要除以最大灰度值255即可。
train_set_x = train_set_x_flatten/255.
test_set_x = test_set_x_flatten/255.
这样我们把数据处理成我们想要的了。
def sigmoid(z):
return 1/(1 + np.exp(-z))
def initialize_with_zeros(dim):
"""
逻辑回归中的参数可以初始化为0,这输入的是w的维数,通常就是输入x的特征数
"""
### START CODE HERE ### (≈ 1 line of code)
w = np.zeros((dim,1))
b = 0
return w, b
def propagate(w, b, X, Y):
"""
实现逻辑回归中的正向传播和反向传播
Arguments:
w -- 权值向量 (num_px * num_px * 3, 1)
b -- 偏差, 标量
X -- 输入数据X (num_px * num_px * 3, 样本数)
Y -- true "label" vector (0 非猫, 1 猫) of size (1, 样本数)
Return:
cost -- 逻辑回归的损失值
dw -- dL/dw
db -- dL/db
"""
m = X.shape[1]#样本数
# 前向传播,从X到cost
A = sigmoid(np.dot(w.T,X) + b) #计算激活值
cost = -1.0/m * (np.dot(Y,np.log(A).T) + np.dot(1-Y,np.log(1-A).T)) #计算损失
# 反向传播,求梯度
dw = np.dot(X,(A-Y).T) / m
db = np.squeeze(np.mean((A - Y),axis=1))
grads = {"dw": dw,
"db": db}
return grads, cost
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):
"""
优化参数的函数
Arguments:
w -- 权值向量 (num_px * num_px * 3, 1)
b -- 偏差, 标量
X -- 输入数据X (num_px * num_px * 3, 样本数)
Y -- true "label" vector (0 非猫, 1 猫) of size (1, 样本数)
num_iterations -- 迭代次数
learning_rate -- 学习率
print_cost -- 是否打印损失值信息
Returns:
params -- 包含w和b的字典
grads -- 包含dL/dw和dL/db的字典
costs -- 优化过程中的损失值,可以用来画学习曲线
"""
costs = []#记录每100次迭代后的损失值
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
# Record the costs
if i % 100 == 0:
costs.append(cost)
# Print the cost every 100 training iterations
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
def predict(w, b, X):
'''
给定参数,预测X的输出,
返回
1:猫
0:非猫
'''
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) # (1,m)
# 将概率转换为输出
for i in range(A.shape[1]):
Y_prediction[0,i] = 1 if A[0,i] > 0.5 else 0
return Y_prediction
所有用到的函数都写好了,接下来将它们整合到一个函数中,并进行训练,最后来预测我们自己的猫图片。
# GRADED FUNCTION: model
def model(X_train, Y_train, X_test, Y_test, num_iterations = 2000, learning_rate = 0.5, print_cost = False):
"""
调用上面实现的函数来构建逻辑回归模型
"""
# 初始化参数,传入特征数n_x
w, b = initialize_with_zeros(X_train.shape[0])
# 梯度下降
parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations= num_iterations, learning_rate = learning_rate, print_cost = 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("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100))
print("test accuracy: {} %".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 = 2000, learning_rate = 0.005, print_cost = True)
在训练集上的准确率挺高,在测试集上的准确率有70%。我们关注的其实是在测试集上的准确率,这里显然过拟合了。
但是比基准模型(随机选,50%)好多了。
最后用我们训练得到的模型来预测自己的图片。
from skimage import io,transform
num_px = 64 #为了和我们训练样本的维度保持一致
my_image = "test_1.jpg" #待预测的图片
fname = "images/" + my_image
image = io.imread(fname)#读取图片,得到numpy array
print(image.shape)
image = image/255.#归一化
# 进行图片大小转换后才能进行reshape
image = transform.resize(image,(num_px,num_px)).reshape((1, num_px*num_px*3)).T
# 预览图片
plt.imshow(image.reshape((num_px, num_px, 3)))
# 用训练得到的w和b进行预测
my_predicted_image = predict(d["w"], d["b"], image)
# 打印预测结果
print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") + "\" picture.")
这里用skimage
来处理图像,个人觉得这个包比PIL方便多了,skimage
直接返回numpy
数组,推荐大家使用。
这里试三个图片。
第一张图片是一只老虎,我们知道它也是猫科动物,看我们的模型能否预测正确。
输出0,预测正确,可以看到图像被压缩后的效果:
第二张图片是一只可爱的猫。
输出1,哈哈,预测正确。
最后试一下赛亚人卡卡罗特。
我们的模型竟然说童年卡卡罗特是猫,这里显然预测错了。
64*64*3=12288
个像素的图片中预测结果就是这样的。虽然图片看起来不清晰,其实也有1W多个特征了。当然因为我们学习的是彩色图片,其实可以先将它们转换成黑白图片,然后再训练,最后看看结果怎样。
感兴趣的同学可以试下,这里贴出转换黑白图片的代码。
from skimage import io,color
my_image = "test_1.jpg" # change this to the name of your image file
fname = "images/" + my_image
rgb=io.imread(fname)
image = color.rgb2gray(rgb)
io.imshow(image)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。