当前位置:   article > 正文

用逻辑回归实现图像识别_使用逻辑回归模型实现手写体图像数字的识别,并对学习结果进行可视化

使用逻辑回归模型实现手写体图像数字的识别,并对学习结果进行可视化

引言

为了更好的掌握吴恩达深度学习——神经网络基础中的理论知识。跟我一起来看下如何用逻辑回归来实现图像识别算法,识别一个图像中有没有含有猫(实际上就是二分类问题)。

关于本文代码中的公式推导可见吴恩达深度学习——神经网络基础

这是吴恩达深度学习第一节课的作业,如果你也在学习吴恩达深度学习教程,并且未做作业的话,建议你关闭该网页,根据作业指导自己实现代码先。

数据集

首先来看下我们的数据集。

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

上面是加载数据集的代码,数据集下载

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述
我们看下数据集的样子,从输出可以看到,有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))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

输出为:

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)
  • 1
  • 2
  • 3
  • 4

通常对于图像数据需要进行归一化处理,这里只要除以最大灰度值255即可。

train_set_x = train_set_x_flatten/255.
test_set_x = test_set_x_flatten/255.
  • 1
  • 2

这样我们把数据处理成我们想要的了。

代码实现

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


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120

所有用到的函数都写好了,接下来将它们整合到一个函数中,并进行训练,最后来预测我们自己的猫图片。

# 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

这里通过面向过程的思想实现了我们逻辑回归的模型,现在我们训练一下看下准确率如何吧。

d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 2000, learning_rate = 0.005, print_cost = True)
  • 1

在这里插入图片描述
在训练集上的准确率挺高,在测试集上的准确率有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.")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

这里用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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/262362
推荐阅读
相关标签
  

闽ICP备14008679号