专栏首页CSDN博客使用Logistic回归实现猫的二分类

使用Logistic回归实现猫的二分类

原文博客:Doi技术团队 链接地址:https://blog.doiduoyi.com/authors/1584446358138 初心:记录优秀的Doi技术团队学习经历

目录

文章目录

  • 目录
  • 前言
  • 导入包
  • 获取数据
  • 学习算法的一般体系结构
    • 定义模型结构
      • 定义sigmoid函数
      • 定义计算损失值函数
    • 初始化模型的参数
    • 定义梯度下降算法
  • 使用Logistic预测
  • 将所有功能合并到模型中
  • 测试各种的学习率对模型收敛的效果
  • 预测自己的图像
  • 启动训练
  • 全部代码
  • 参考资料

前言

这里使用到的是一个猫的数据集,根据这个数据集训练图像是不是猫,数据集的图像如下:

导入包

如果没有安装对应的包,请使用pip安装对应的包,这个使用了一个lr_utils的工具类,这个工具类是加载数据集的工具,可以到这里下载。这个工具类也使用一个h5py,所以也要安装该包。

# coding=utf-8
import matplotlib.pyplot as plt
import numpy as np
import scipy
from scipy import ndimage
from lr_utils import load_dataset

获取数据

接下来就是加载数据和对数据进行处理

# 加载数据
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()

# 读取图像的大小
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)大小转成numpy数据的(num_px ∗ num_px ∗ 3, 1).
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

# 对数据集进行居中和标准化
train_set_x = train_set_x_flatten / 255.
test_set_x = test_set_x_flatten / 255.

学习算法的一般体系结构

  1. 定义模型结构(例如输入特性的数量)
  2. 初始化模型的参数
  3. 循环:
    • 计算当前损失(正向传播)
    • 计算当前梯度(向后传播)
    • 更新参数(梯度下降)

定义模型结构

定义sigmoid函数

def sigmoid(x):
    """
    计算sigmoid函数
    :param x: 任意大小的标量或者numpy数组
    :return: sigmoid(x)
    """
    s = 1 / (1 + np.exp(-x))
    return s

定义计算损失值函数

def propagate(w, b, X, Y):
    """
    实现上述传播的成本函数及其梯度
    :param w: 权重,一个numpy数组大小(num_px * num_px * 3,1)
    :param b: 偏差,一个标量
    :param X: 数据大小(num_px * num_px * 3,例子数量)
    :param Y: 真正的“标签”向量(包含0如果非猫,1如果猫)的大小(1,例子数量)
    :return: 
    cost -- Logistic回归的负对数似然成本。
    dw -- 关于w的损失梯度,与w相同。
    db -- 关于b的损失梯度,与b相同。
    """
    m = X.shape[1]
    A = sigmoid(np.add(np.dot(w.T, X), b))  # compute activation
    cost = -(np.dot(Y, np.log(A).T) + np.dot(1 - Y, np.log(1 - A).T)) / m  # compute cost
    dw = np.dot(X, (A - Y).T) / m
    db = np.sum(A - Y) / m
    assert (dw.shape == w.shape)
    assert (db.dtype == float)
    cost = np.squeeze(cost)
    assert (cost.shape == ())
    grads = {"dw": dw,
             "db": db}

    return grads, cost

初始化模型的参数

开始给权重值和偏差初始化一个值,权重是一个矢量,偏差是一个标量。

def initialize_with_zeros(dim):
    """
    这个函数为w创建一个形状为0的向量(dim, 1),并初始化b为0。
    :param dim: 我们想要的w向量的大小(或者这个例子中的参数个数)
    :return: 
    w -- 初始形状矢量(dim, 1)
    b -- 初始化标量(对应于偏差)
    """
    w = np.zeros((dim, 1))
    b = 0
    assert (w.shape == (dim, 1))
    assert (isinstance(b, float) or isinstance(b, int))
    return w, b

定义梯度下降算法

通过以下的公式规则来更新参数:

def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost=False):
    """
    该函数通过运行梯度下降算法优化w和b
    :param w: 权重,一个numpy数组大小(num_px * num_px * 3,1)
    :param b: 偏差,一个标量
    :param X: 数据大小 (num_px * num_px * 3, 例子数量)
    :param Y: 真正的“标签”向量(包含0,如非猫,1如果猫),形状(1,例子数量)
    :param num_iterations: 优化循环的迭代次数
    :param learning_rate: 梯度下降更新规则的学习速率
    :param print_cost: 确实每100步就打印一次损失
    :return: 
    params -- 字典中包含权重w和偏差b。
    grads -- 字典中包含权重的梯度和关于成本函数的梯度。
    costs -- 在优化过程中计算的所有成本列表,将用于绘制学习曲线。
    """
    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

使用Logistic预测

当激活值小于等于0.5时,结果是0,如果激活值大于0.5时,结果是1。

def predict(w, b, X):
    """
    使用学习的逻辑回归参数预测标签是否为0或1 (w, b)
    :param w: 权重,一个numpy数组大小(num_px * num_px * 3,1)
    :param b: 偏差,一个标量
    :param X: 数据大小 (num_px * num_px * 3, 样本数量)
    :return: 
    Y_prediction -- 一个包含所有关于X中的例子的所有预测(0/1)的numpy数组(vector)。 
    """
    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]):
        if A[0, i] <= 0.5:
            Y_prediction[0, i] = 0
        else:
            Y_prediction[0, i] = 1
    assert (Y_prediction.shape == (1, m))
    return Y_prediction

将所有功能合并到模型中

把刚才编写好的函数:初始化函数,优化参数函数和预测函数整合到这个model函数统一处理:

def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):
    """
    通过调用之前实现的函数构建逻辑回归模型。
    :param X_train: 由形状的numpy数组表示的训练集(num_px * num_px * 3, m_train)
    :param Y_train: 由形状(1,m_train)的numpy阵列(矢量)表示的训练标签
    :param X_test: 由形状的numpy数组表示的测试集(num_px * num_px * 3, m_test)
    :param Y_test: 由形状(1,m_test)的numpy数组(vector)表示的测试标签
    :param num_iterations: 表示要优化参数的迭代次数的超参数。
    :param learning_rate: 表示optimize()更新规则中使用的学习速率的超参数
    :param print_cost: 设置为true,每100次迭代打印成本。
    :return: 
    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 = 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

测试各种的学习率对模型收敛的效果

尝试不同的学习率,可以得到最好的训练效果。学习率决定我们更新参数的速度。如果学习率过高,我们可能会“超过”最优值。同样,如果它太小,我们将需要太多迭代才能收敛到最佳值,所以一个好的学习率至关重要。

def test_anther_lr():
    learning_rates = [0.01, 0.001, 0.0001]
    models = {}
    for i in learning_rates:
        print ("learning rate is: " + str(i))
        models[str(i)] = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations=1500,
                               learning_rate=i, print_cost=False)
        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 (hundreds)')

    legend = plt.legend(loc='upper center', shadow=True)
    frame = legend.get_frame()
    frame.set_facecolor('0.90')
    plt.show()

预测自己的图像

通过这个函数,可以是个模型字典的参数就可以获取预测结果了。通过接收图像修该成训练时的图像大小。要注意的是只接受JPG格式的图像。

def infer_mydata(my_image, d):
    """
    预测自己的图像
    :param my_image: 图像名字,只接受jpg格式
    :param d: 训练好的模型信息的字典
    :return: 
    """
    fname = "images/" + my_image
    image = np.array(ndimage.imread(fname, flatten=False))
    my_image = scipy.misc.imresize(image, size=(num_px, num_px)).reshape((1, num_px * num_px * 3)).T
    my_predicted_image = predict(d["w"], d["b"], my_image)

    plt.imshow(image)
    print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[
        int(np.squeeze(my_predicted_image)),].decode("utf-8") + "\" picture.")

启动训练

在这里可以调用model()函数进行训练模型,获得训练后的模型信息的字典,使用这些字典就可以预测图像了。 通过调用infer_mydata()这个函数就可以预测图像了,这个要注意的是,图像只支持JPG格式。 test_anther_lr()函数是使用不用的学习率来观察不同学习率的收敛情况。

if __name__ == "__main__":
    d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations=1000, learning_rate=0.005,
              print_cost=True)
    # infer_mydata('cat2.jpg', d)
    # test_anther_lr()

输出结果如下:

Cost after iteration 0: 0.693147
Cost after iteration 100: 0.584508
Cost after iteration 200: 0.466949
Cost after iteration 300: 0.376007
Cost after iteration 400: 0.331463
Cost after iteration 500: 0.303273
Cost after iteration 600: 0.279880
Cost after iteration 700: 0.260042
Cost after iteration 800: 0.242941
Cost after iteration 900: 0.228004
train accuracy: 96.6507177033 %
test accuracy: 72.0 %

全部代码

为了方便阅读代码,笔者把这篇的所有代码都放出来了:

# coding=utf-8
import matplotlib.pyplot as plt
import numpy as np
import scipy
from scipy import ndimage
from lr_utils import load_dataset

# 加载数据
train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = load_dataset()

# 读取图像的大小
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)大小转成numpy数据的(num_px ∗ num_px ∗ 3, 1).
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

# 对数据集进行居中和标准化
train_set_x = train_set_x_flatten / 255.
test_set_x = test_set_x_flatten / 255.


# 定义sigmoid函数
def sigmoid(x):
    """
    计算sigmoid函数
    :param x: 任意大小的标量或者numpy数组
    :return: sigmoid(x)
    """
    s = 1 / (1 + np.exp(-x))
    return s


# 初始化权重值和偏差
def initialize_with_zeros(dim):
    """
    这个函数为w创建一个形状为0的向量(dim, 1),并初始化b为0。
    :param dim: 我们想要的w向量的大小(或者这个例子中的参数个数)
    :return: 
    w -- 初始形状矢量(dim, 1)
    b -- 初始化标量(对应于偏差)
    """
    w = np.zeros((dim, 1))
    b = 0
    assert (w.shape == (dim, 1))
    assert (isinstance(b, float) or isinstance(b, int))
    return w, b


# 通过正向传播和反向传播计算损失值
def propagate(w, b, X, Y):
    """
    实现上述传播的成本函数及其梯度
    :param w: 权重,一个numpy数组大小(num_px * num_px * 3,1)
    :param b: 偏差,一个标量
    :param X: 数据大小(num_px * num_px * 3,例子数量)
    :param Y: 真正的“标签”向量(包含0如果非猫,1如果猫)的大小(1,例子数量)
    :return: 
    cost -- Logistic回归的负对数似然成本。
    dw -- 关于w的损失梯度,与w相同。
    db -- 关于b的损失梯度,与b相同。
    """
    m = X.shape[1]
    A = sigmoid(np.add(np.dot(w.T, X), b))  # compute activation
    cost = -(np.dot(Y, np.log(A).T) + np.dot(1 - Y, np.log(1 - A).T)) / m  # compute cost
    dw = np.dot(X, (A - Y).T) / m
    db = np.sum(A - Y) / m
    assert (dw.shape == w.shape)
    assert (db.dtype == float)
    cost = np.squeeze(cost)
    assert (cost.shape == ())
    grads = {"dw": dw,
             "db": db}

    return grads, cost


# 通过梯度下降算法来优化w和b
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost=False):
    """
    该函数通过运行梯度下降算法优化w和b
    :param w: 权重,一个numpy数组大小(num_px * num_px * 3,1)
    :param b: 偏差,一个标量
    :param X: 数据大小 (num_px * num_px * 3, 例子数量)
    :param Y: 真正的“标签”向量(包含0,如非猫,1如果猫),形状(1,例子数量)
    :param num_iterations: 优化循环的迭代次数
    :param learning_rate: 梯度下降更新规则的学习速率
    :param print_cost: 确实每100步就打印一次损失
    :return: 
    params -- 字典中包含权重w和偏差b。
    grads -- 字典中包含权重的梯度和关于成本函数的梯度。
    costs -- 在优化过程中计算的所有成本列表,将用于绘制学习曲线。
    """
    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


# 使用Logistic预测
def predict(w, b, X):
    """
    使用学习的逻辑回归参数预测标签是否为0或1 (w, b)
    :param w: 权重,一个numpy数组大小(num_px * num_px * 3,1)
    :param b: 偏差,一个标量
    :param X: 数据大小 (num_px * num_px * 3, 样本数量)
    :return: 
    Y_prediction -- 一个包含所有关于X中的例子的所有预测(0/1)的numpy数组(vector)。 
    """
    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]):
        if A[0, i] <= 0.5:
            Y_prediction[0, i] = 0
        else:
            Y_prediction[0, i] = 1
    assert (Y_prediction.shape == (1, m))
    return Y_prediction


# 将所有功能合并到模型中
def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):
    """
    通过调用之前实现的函数构建逻辑回归模型。
    :param X_train: 由形状的numpy数组表示的训练集(num_px * num_px * 3, m_train)
    :param Y_train: 由形状(1,m_train)的numpy阵列(矢量)表示的训练标签
    :param X_test: 由形状的numpy数组表示的测试集(num_px * num_px * 3, m_test)
    :param Y_test: 由形状(1,m_test)的numpy数组(vector)表示的测试标签
    :param num_iterations: 表示要优化参数的迭代次数的超参数。
    :param learning_rate: 表示optimize()更新规则中使用的学习速率的超参数
    :param print_cost: 设置为true,每100次迭代打印成本。
    :return: 
    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 = 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


# 测试各种的学习率对模型收敛的效果
def test_anther_lr():
    learning_rates = [0.01, 0.001, 0.0001]
    models = {}
    for i in learning_rates:
        print ("learning rate is: " + str(i))
        models[str(i)] = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations=1500,
                               learning_rate=i, print_cost=False)
        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 (hundreds)')

    legend = plt.legend(loc='upper center', shadow=True)
    frame = legend.get_frame()
    frame.set_facecolor('0.90')
    plt.show()


# 预测自己的图像
def infer_mydata(my_image, d):
    """
    预测自己的图像
    :param my_image: 图像名字,只接受jpg格式
    :param d: 训练好的模型信息的字典
    :return: 
    """
    fname = "images/" + my_image
    image = np.array(ndimage.imread(fname, flatten=False))
    my_image = scipy.misc.imresize(image, size=(num_px, num_px)).reshape((1, num_px * num_px * 3)).T
    my_predicted_image = predict(d["w"], d["b"], my_image)

    plt.imshow(image)
    print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[
        int(np.squeeze(my_predicted_image)),].decode("utf-8") + "\" picture.")


if __name__ == "__main__":
    d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations=1000, learning_rate=0.005,
              print_cost=True)
    # infer_mydata('cat2.jpg', d)
    # test_anther_lr()

参考资料

  1. http://deeplearning.ai/

该笔记是学习吴恩达老师的课程写的。初学者入门,如有理解有误的,欢迎批评指正!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 《PaddlePaddle从入门到炼丹》十——VisualDL 训练可视化

    VisualDL是一个面向深度学习任务设计的可视化工具,包含了scalar、参数分布、模型结构、图像可视化等功能。可以这样说:“所见即所得”。我们可以借助Vis...

    夜雨飘零
  • 百度机器学习训练营笔记——数学基础

    μ=1N∑i=1Nxi(x:x1,x2,...,xN)\mu=\frac{1}{N}\sum_{i=1}^Nx_i\left(x:x_1,x_2,...,x_N...

    夜雨飘零
  • 《我的PaddlePaddle学习之路》笔记八——场景文字识别

    在前两篇文章验证码端到端的识别和车牌端到端的识别这两篇文章中其实就使用到了场景文字识别了,在本篇中就针对场景文字识别这个问题好好说说。

    夜雨飘零
  • 吴恩达深度学习笔记 course3 week2 机器学习 策略(2)

    例:当我们在训练一个模型的时候,我们的准确率是90%,bayes optimized bias是0%,这个时候错误率达到了10%,那么我们如何分析是哪错了,并且...

    Dar_Alpha
  • 第07期:有关 MySQL 字符集的 SQL 语句

    翻译过来就是字符引导。也就是针对字符串,显式的给定一个字符编码和排序规则,不受系统参数的影响。

    爱可生开源社区
  • 【一起学源码-微服务】Nexflix Eureka 源码六:在眼花缭乱的代码中,EurekaClient是如何注册的?

    上一讲已经讲解了EurekaClient的启动流程,到了这里已经有6篇Eureka源码分析的文章了,看了下之前的文章,感觉代码成分太多,会影响阅读,后面会只截取...

    一枝花算不算浪漫
  • c++STL容器之set/multiset容器

    绝命生
  • Dubbo + RestEasy 实现文件上传与下载

    原文链接:https://blog.csdn.net/weixin_43057263/article/details/...

    微风-- 轻许--
  • vim设置大括号自动补全并换行缩进【工具】

    一 在vim中,打出一个大括号后,自动补全另一个大括号并换行 鼠标定位在换行后缩进的位置

    sinnoo
  • linux中权限管理命令详解(chmod/chown/chgrp/unmask)

    Linux操作系统对多用户的管理,是非常繁琐的,所以用组的概念来管理用户就变得简单,每个用户可以在一个独立的组,每个组也可以有零个用户或者多个用户。本文给大家介...

    砸漏

扫码关注云+社区

领取腾讯云代金券