回归问题

前言

深度学习其实主要就是梯度下降,谁的梯度下降做的好,谁的网络就更精确,更好。梯度就是深度学习的核心精髓。

梯度下降算法相当于就是去求解一个函数。

回归问题

我们再求解一个函数的极值的时候一般都是求他的导数,然后找出导数值为0时x的取值。

梯度下降跟这个也很类似,就是要找出损失函数的极小值。而要找出他的极小值就要通过导数对x坐标进行修正。直到找出那个导数为0的。

公式为:x′=x−dydxx'=x-\frac{dy}{dx}x=xdxdy (注意,这是一个不断迭代的过程,第一次计算结束后得到的x′x'x就是下一次计算的xxx)

参数意义:xxx是当前xxx值,dydx\frac{dy}{dx}dxdy是当前x处的导数值,x′x'x是当前经过修正之后得到的新的xxx的值

简单理解就是一直用函数的变化率去修正,如果函数变化率(下面称导数)为正,那么就会往x轴的左边移动,如果导数值为负,就会往x轴的右边移动,当导数值为0,x减去0还是x,也就是说这个时候的这个点就是导数等于0的点(因为再怎么减也不变了)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0wNXiOw-1591279465382)(E:\Programing Project\Git\Summary\pytorch-note\回归问题\imgs\1.png)]

  • 其实就是通过迭代来找到导数值等于0的点

在每一次迭代过程中都会在导数值处乘一个数值,公式表示为:x′=x−αdydxx'=x-\alpha\frac{dy}{dx}x=xαdxdy.

这个α\alphaα就是学习率。

  • 可以理解为这个是调整每次下降的幅度的,因为学习率是在[0,1][0,1][0,1]之间的所以,用学习率α\alphaα乘导数值时相当于减少了导数值的大小,也就是每次下降都不会那么多,可以多次下降,细化区间。因为分的越细,能找到导数等于0的地方的可能性越大,如果每次下降幅度过大,那么回调参数的时候也会幅度过大,导致很难找到导数为0的点。(也就是极值点)就是调整缩放倍数

梯度下降的本质就是通过迭代找到导数为0的点。

优化器(optimizer)

  • 优化器其实就是对梯度下降进行一个优化,让梯度下降有更大的概率能够找到导数值为0的点

    也就是极值点。一般优化器可能会考虑上一次前进或后退的方向等方面因素,帮助梯度下降更好地找到loss最低的点。

  • 就是给梯度下降增加各种各样的约束条件,但最终目的还是让梯度下降有更大的概率找到极值点(导数等于0的点)。同时有些算法也能够让梯度下降更快地找到极值点。

常用求解器:Adam、SGD、rmsprop

数据误差(线性方程组)

在求解实际问题的时候,我们不用追求完全百分之百的准确值,只要求得的结果在可接受的误差范围之内,就是能够被我们能够使用的数据。

因为现实中不论是获取的数据还是计算出来的数据都会存在有一定的误差,就像物理实验、化学实验等会有许多误差,所以我们通过对误差的研究,就可以得到更接近于我们现实生活中的数据。

因此我们需要引入噪声数据。(也就是与实际具有偏差的数据,可以理解为误差。可以是人为的、系统的、随机的误差,各种方方面面的影响因素。)

设一个线性方程:y=wx+by=wx+by=wx+b

比如我们在计算一个二元一次方程组的时候:

{1.567=w∗1+b3.043=w∗2+b\begin{cases}1.567=w*1+b\\3.043=w*2+b\end{cases}{1.567=w1+b3.043=w2+b

上面这个方程组是我们理论上的方程组。

但实际中,因为误差,所以我们也要在求解的过程中引入。但引入误差意味着增加了变量的个数,此时,我们就需要更多的方程来帮我们解出这个方程组。

如:

y=wx+b+ϵy=wx+b+\epsilony=wx+b+ϵ

我们引入高斯噪声ϵ∈[0.01,1]\epsilon\in[0.01,1]ϵ[0.01,1]上面的方程组就变为:

{1.567=w∗1+b+ϵ3.043=w∗2+b+ϵ4.519=w∗3+b+ϵ\begin{cases}1.567=w*1+b+\epsilon\\3.043=w*2+b+\epsilon\\4.519=w*3+b+\epsilon\end{cases}1.567=w1+b+ϵ3.043=w2+b+ϵ4.519=w3+b+ϵ

所以在求解实际问题中可能我们需要解一个几百个方程的方程组,这时候我们就要用到我们的矩阵了,所以,求解这么一个方程组可以转换为求一个线性方程组的解也就是

ypred=WX+by_{pred}=WX+bypred=WX+b

loss=(ypred−yreal)2=(WX+b−yreal)2loss=(y_{pred}-y_{real})^2=(WX+b-y_{real})^2loss=(ypredyreal)2=(WX+byreal)2

这里,我们不是仅仅求losslossloss的最小值,而是求ypredy_{pred}ypredyrealy_{real}yreal之间的差值最小,因为当预测值和真实值之间的差距越小,说明这个预测值就越接近真实值,所以我们通过一个做差然后再代入一个y=x2y=x^2y=x2的函数里面进行求最小值。所以也就得到了loss=(WX+b−yreal)2loss=(WX+b-y_{real})^2loss=(WX+byreal)2也就是求yrealy_{real}yrealypredy_{pred}ypred差的最小值。

所以我们通过求losslossloss的极小值,就可以得到ypredy_{pred}ypredyrealy_{real}yreal之间的最小值了。(因为y=x2y=x^2y=x2的最小值就是000,只要yyy小,xxx也会小)

  • 其实也就是类似求一个线性回归的问题。通过均值找到wwwbbb,这个wwwbbb的参数所形成的直线周围尽可能多的落入更多的点。

优化过程

  • loss=∑i(w∗xi+b−yi)2loss=\sum_{i}(w*x_i+b-y_i)^2loss=i(wxi+byi)2

  • 求loss的最小值

  • 得到最优解w′w'wb′b'b

    使得这个把xxx代入之后得到的ypredy_{pred}ypred接近yrealy_{real}yreal

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-royhLtUd-1591279465385)(E:\Programing Project\Git\Summary\pytorch-note\回归问题\imgs\2.png)]

在高维的求导中我们无法用图像显示出它的过程,但我们需要知道,核心就是求解梯度下降下降得最快的位置,也就是梯度方向(如果放在三维里的话。)

几种回归类型

  1. 线性回归

    就是通过大量的数据计算出wwwbbb的值。而yyy是属于实数空间中的,这种就是叫做线性回归。(也就是线性回归方程组)就是我们要预测的值就是一个连续的值。

  2. 逻辑回归

    就是在线性回归的基础上在最后加入了一个激活函数,把数据进行压缩。把数据压缩到[0,1][0,1][0,1]之间。好处就是可以直接把问题转化成概率问题

实战

  1. 计算losslossloss

loss=∑i(w∗xi+b−yi)2loss=\sum_{i}(w*x_i+b-y_i)^2loss=i(wxi+byi)2

def compute_error_for_line_give_points(b,w,points): # 计算损失
    """
    b:当前的b值
    w:当前的w值
    points:list 点的列表
    """
	totalError = 0
	for i in range(0,len(points)):
        x = points[i,0]
        y = points[i,1]
        totalError += (y-(w * x + b)) ** 2
	return totalError / float(len(points))

# 上面就是求一个均值

对于每一个点都进行循环迭代。

  1. 计算梯度

losslossloss函数求偏导:

∂loss∂w=2(WX+b−y)X\frac{\partial loss}{\partial w}=2(WX+b-y)Xwloss=2(WX+by)X

∂loss∂b=2(WX+b−y)\frac{\partial loss}{\partial b}=2(WX+b-y)bloss=2(WX+by)

def step_gradient(b_current, w_current, points, learningRate):
    b_gradient = 0 # 每次都对梯度置零
    w_gradient = 0 # 每次都对梯度置零
    N = float(len(points))
    # 计算梯度
    for i in range(0,len(points)):
        x = points[i,0]
        y = points[i,1]
        b_gradient += -(2 / N) * (y - ((w_current * x ) + b_current))
        w_gradient += -(2 / N) * x * (y - ((w_current * x ) + b_current))
    # 参数修正
	new_b = b_current - (learningRate * b_current)
    new_w = w_current - (learningRate * w_current)
   	return [new_b, new_w]
  1. 进行循环迭代
def gradient_decent_runner(points, starting_b, starting_w, 
                           learningRate, num_iterations):
    b = starting_b
    w = starting_w
    for i in range(num_iterations):
        b, w = step_gradient(b, w, np.array(points), learningRate)
        
    return [b, w]
  1. 运行
def run():
    points = np.genfromtxt('data.csv', delimiter=',')
    learning_rate = 0.00001
    init_b = 0
    init_w = 0
    num_iterations = 1000
    print('Starting gradient descent at b = %f, w = %f, error =%f' % (
        init_b, init_w, compute_error_for_line_give_points(init_b, init_w, points)))
    print('Running...')
    [b, w] = gradient_decent_runner(points, init_b, init_w, learning_rate, num_iterations)
    print('After %d iterations b = %f, w = %f, error = %f' % (
        num_iterations, b, w, compute_error_for_line_give_points(b, w, points)))

总结

梯度下降的流程

  • 注:梯度下降x和y是已知量,要求的是w和b

确定损失函数–>初始化b和w–>初始化b和w梯度值,x代入导数值求梯度–>用梯度来更新b和w的值–>重复迭代

更多推荐