demo1-2逻辑回归-图片中猫的识别

本文声明:本文参考深度学习-Stanford吴恩达教授的文章,思路以及代码。基于他的文章(希望大家直接去看原作者的优秀文章【深度学习-Stanford吴恩达教授】,这篇博客仅为了记录自己的学习过程),形成了自己的理解,希望总结成自己的经验与知识,于是发表了这篇博客,如有不妥的地方欢迎大家指正。(若有侵权可联系我进行删除,刚开始写没有经验)

一,Logistic回归之神经网络搭建

1,Logistic 回归

  (Logistic Regression)逻辑回归算法适用于二分零算法,这里主要讲逻辑回归的Hypothesis Function(假设函数)。

  对于二元分类问题来讲,给定一个输入特征向量 X = {x1,x2,x3,…},它可能对应一张图片,你想识别这张图片识别看它是否是一只猫或者不是一只猫的图片,你想要一个算法能够输出预测,,你只能称之为y,也就是你对实际值y的估计。更正式的说:你想让y表示等于y等于1的一种可能性或者是机会,前提条件是给定了输入特征X。

X是一个nx维的向量(相当于nx个特征的特征向量),我们用w表示逻辑回归的参数,这也是一个nx维向量(因为w实际上是特征权重,维度与特征向量相同),参数里面还有个b,表示偏差。 所以给出输入x以及参数w和b之后,我们怎样产生输出预测值y,答案就是:y = wTx + b。
模型的输出输出

2,sigmoid函数

​  ​我们通过yh = wTx + b得到一个关于输入x的线性函数,实际上这是在做线性回归时所用到的,但是这对于二元分类来讲并不是一个非常好的算法,因为你想让yh表示实际值y等于1的机率的话,yh应该在0到1之间。这是一个需要解决的问题,因为wTx + b可能比1要大得多,或者甚至为一个负值。对于你想要的在0和1亿间的概率来说它是没有意义的。

​​  因此在逻辑回归中,我们的输出yh应该是等于由上面得到的线性函数式子作为自变量的sigmoid函数中,公式如上图最下面所示,将线性函数转换为非线性函数。

​  下图是sigmoid函数的图像,如果我把水平轴作为z轴,那么关于z的sigmoid函数是这样的,它是平滑地从0走向1,让我在这里标记纵轴,这是0,曲线与纵轴相交的截距是0.5,这就是关于的sigmoid函数的图像。 我们通常都使用z来表示wTx十b的值。
sigmoid函数
​​  关于sigmoid函数的公式是这样的,σ(z)= 1 / (1 + e-z),在这里z是一个实数,这里要说明一些要注意的事情,如果z非常大那么e-z将会接近于0,关于z的sigmoid函数将会近似等于1除以1加上某个非常接近于0的项,因为e的指数如果是个绝对值很大的负数的话,这项将会接近于0,所以如果z很大的话那么关于z的sigmoid函数会非常接近1。相反地,如果z非常小或者说是一个绝对值很大的负数,那么关于e-z这项会变成一-个很大的数,你可以认为这是1除以1加上一个非常非常大的数,所以这个就接近于0。实际上你看到当z变成一个绝对值很大的负数,于z的sigmoid函数就会非常接近于0,

​​  因此当你实现逻辑回归时,你的工作就是去让机器学习参数w以及b,这样才使得y^^^成为对y = 1这一情况的概率的一个很好的估计。

#现在构建sigmoid(),需要使用 sigmoid(w ^ T x + b) 计算来做出预测。
def sigmoid(z) :
    """
    :param z:任何大小的标量或numpy数组。
    :return:sigmoid(z)
    """
    s = 1 / (1 + np.exp(-z))
    return s

print("==========测试sigmoid函数==========")
print("sigmoid(0) = " + str(sigmoid(0)))
print("sigmoid(10) = " + str(sigmoid(10)))

运行结果:
==========测试sigmoid函数==========
sigmoid(0) = 0.5
sigmoid(10) = 0.9999546021312976
3,Logistic 回归[损失函数

​​  损失函数(Cost Function)为什么需要代价函数:为了训练逻辑回归模型的参数w和参数b,我们需要一个代价函数,通过训练代价函数来得到参数w和参数b。先看一下逻辑回归的输出函数:
在这里插入图片描述
为了让模型通过学习调整参数,你需要给予一个m样本的训练集,这会让你在训练集上找到参数w和参数b,来得到你的输出。

​​  对训练集的预测值,我们将它写成y^^^,我们更希望它会接近于训练集中的y值(已大打好标签,在二分类里里面为0 / 1),为了对上面的公式更详细的介绍,我们需要说明上面的定义是对一个训练样本来说的,这种形式也使用于每个训练样本,我们使用这些带有圆括号的上标来区分索引和样本,训练样本i所对应的预测值是y(i),是用训练样本的wTx(i) + b然后通过sigmoid函数来得到,也可以把z定义为z(i) = wTx(i) + b,我们将使用这个符号(i)注解,上标(i)来指明数据表示x或者y或者z或者其他数据的第i个训练样本,这就是上标(i)的含义。

​​  **损失函数(Loss function):**损失函数又叫做误差函数,用来衡量算法的运行情况,Loss function: L(y^^^ ,y)。我们通过这个称为L的损失函数,来衡量预测输出值和实际值有多接近。一般我们用预测值和实际值的平方差或者它们平方差的一半,但是通常在逻辑回归中我们不这么做,因为当我们在学习逻辑回归参数的时候,会发现我们的优化目标不是凸优化,只能找到多个局部最优值,梯度下降法很可能找不到全局最优值,虽然平差是一个不错的损失函数,但是我们在逻辑回归模型中会定义另外一个损失函数。我们在逻辑回归中用到的损失函数是:

​​  ​​  ​​  L(y^^^,y) = -ylog(y^^^) - (1 - y)log(1-y^^^)

在这里插入图片描述

#初始化参数的函数已经构建好了,现在就可以执行“前向”和“后向”传播步骤来学习参数。
#现在要实现一个计算成本函数及其渐变的函数propagate()。
def propagate(w,b,X,Y):
    """
    实现前向和后向传播的成本函数及其梯度。
    参数:
         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的形状相同
    """
    m = X.shape[1]    #m = 209 训练集的图片数量

    #正向传播
    A = sigmoid(np.dot(w.T, X) + b)   #计算激活值 ,参考公式
    cost = (-1 / m) * np.sum(Y * np.log(A) + (1- Y) * (np.log(1 -A)))  #计算成本

    #反向传播  参考公式
    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)

#写好之后我们来测试一下
print("========= 测试propagate =========")
#初始化参数
w = np.array( [[1],[2]] )
b = 2
X = np.array( [ [1,2], [3,4]])
Y = np.array([ [1, 0]])
# print("w = " + str(w))
# print("X = " + str(X))
# print("Y = " + str(Y))

grads, cost = propagate(w,b,X,Y)
print ("dw = " + str(grads["dw"]))
print ("db = " + str(grads["db"]))
print ("cost = " + str(cost))

运行结果:
========= 测试propagate =========
dw = [[0.99993216]
 [1.99980262]]
db = 0.49993523062470574
cost = 6.000064773192205
4,梯度下降法(Gradient Descent)

  度下降法可以做什么:在测试集上,通过最小化代价函数(成本函数)**J(w,b)**来训练参数w和b,前面已学的如下:(即找到)**J(w,b)**值最小时,参数w和b的值)
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

5,Logistic 回归的梯度下降法

​ emsp;这里讨论怎样通过计算偏导数来实现逻辑回归的梯度下降算法。它的关键点几个重要公式,其作用是用来实现逻辑回归中梯度下降算法。但是在本节视频中,我将使用计算图对梯度下降算法进行计算。接下来让我们开始学习逻辑回归的梯度下降算法。
在这里插入图片描述
为了使得逻辑回归中最小代价函数J(a,y),我们仅仅需要修改参数w和b,so仅需要对w和b求偏导:
在这里插入图片描述

'''
现在,我要使用渐变下降更新参数。
目标是通过最小化成本函数J来学习 w和b。
对于参数 θ 更新规则是 $ \theta = \theta - \alpha \text{ } d\theta$,其中 α是学习率。
'''
def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost=False):
    """
    此函数通过运行梯度下降算法来优化w和b
    参数:
        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的梯度下降法则更新参数。
    """
    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)

#现在就让我们来测试一下优化函数:
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= False)
print("w = " + str(params["w"]))
print("b = " + str(params["b"]))
print("dw = " + str(grads["dw"]))
print("db = " + str(grads["db"]))

运行结果:
=========== 测试optimize =======
w = [[0.1124579 ]
 [0.23106775]]
b = 1.5593049248448891
dw = [[0.90158428]
 [1.76250842]]
db = 0.4304620716786828
6,在多个(m个)训练样本下进行以上操作:这里就需要进行向量化操作(相比于for快几个档次)

 emsp;###### 6.1向量化的显著优势:
 emsp;###### 6.2向量化 Logistic 回归
 emsp;###### 6.3向量化 Logistic 回归的梯度输出

7,项目整合
'''
就目前而言,基本上把所有的东西都做完了,
现在我们要把这些函数统统整合到一个model()函数中,
届时只需要调用一个model()就基本上完成所有的事了。
'''
def model(X_train, Y_train, X_test, Y_test, num_iterations=2000, learning_rate=0.5, print_cost=False):
    """
    通过调用之前实现的函数来构建逻辑回归模型

    参数:
        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_prediction_train" : Y_prediction_train,
        "w" : w,
        "b" : b,
        "learning_rate" : learning_rate,
        "num_iterations" : num_iterations
    }

    return d

'''
把整个model构建好之后我们这就算是正式的实际测试了,我们这就来实际跑一下。
'''
print("====================测试model====================")
#这里加载的是真实的数据,请参见上面的代码部分。
d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 2000, learning_rate = 0.005, print_cost = True)
'''

运行结果:
====================测试model====================
迭代的次数: 0 , 误差值: 0.693147
迭代的次数: 100 , 误差值: 0.584508
迭代的次数: 200 , 误差值: 0.466949
迭代的次数: 300 , 误差值: 0.376007
迭代的次数: 400 , 误差值: 0.331463
迭代的次数: 500 , 误差值: 0.303273
迭代的次数: 600 , 误差值: 0.279880
迭代的次数: 700 , 误差值: 0.260042
迭代的次数: 800 , 误差值: 0.242941
迭代的次数: 900 , 误差值: 0.228004
迭代的次数: 1000 , 误差值: 0.214820
迭代的次数: 1100 , 误差值: 0.203078
迭代的次数: 1200 , 误差值: 0.192544
迭代的次数: 1300 , 误差值: 0.183033
迭代的次数: 1400 , 误差值: 0.174399
迭代的次数: 1500 , 误差值: 0.166521
迭代的次数: 1600 , 误差值: 0.159305
迭代的次数: 1700 , 误差值: 0.152667
迭代的次数: 1800 , 误差值: 0.146542
迭代的次数: 1900 , 误差值: 0.140872
训练集准确性: 99.04306220095694 %
测试集准确性: 70.0 %
更改一下学习率和迭代次数,有可能会发现训练集的准确性可能会提高,
但是测试集准确性会下降,这是由于过拟合造成的,但是我们并不需要担心,
以后会使用更好的算法来解决这些问题的。

到目前为止,程序算是完成了,但是还可以在后面加一点东西,比如画点图什么的。

#绘图
costs = np.squeeze(d["costs"])
print("costs = " + str(costs))
plt.plot(costs)
plt.ylabel('costs')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(d["learning_rate"]))
plt.show()

在这里插入图片描述

'''
让我们进一步分析一下,并研究学习率alpha的可能选择。为了让渐变下降起作用,
我们必须明智地选择学习速率。学习率α \alphaα 决定了我们更新参数的速度。
如果学习率过高,我们可能会“超过”最优值。同样,
如果它太小,我们将需要太多迭代才能收敛到最佳值。这就是为什么使用良好调整的学习率至关重要的原因。

我们可以比较一下我们模型的学习曲线和几种学习速率的选择。
也可以尝试使用不同于我们初始化的learning_rates变量包含的三个值,并看一下会发生什么。
'''
learing_rates =[0.01, 0.001, 0.0001]
models = {}

for i in learing_rates:
    print("learing 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 learing_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_faceclor('0.90')
plt.show()

运行结果:
learing rate is : 0.01
训练集准确性: 99.52153110047847 %
测试集准确性: 68.0 %


learing rate is : 0.001
训练集准确性: 88.99521531100478 %
测试集准确性: 64.0 %


learing rate is : 0.0001
训练集准确性: 68.42105263157895 %
测试集准确性: 36.0 %


在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值