梯度下降法(Gradient Descent)初识

梯度下降法(Gradient Descent)

    梯度下降法是用于求解机器学习的算法模型参数(即无约束优化问题)所采用的方法。 梯度下降的作用是最小化一个损失函数。梯度上升则是最大化一个效用函数。

  •     梯度

      在微积分里面,对多元函数的参数求∂偏导数,把求得的各个参数的偏导数以向量的形式写出来,就是梯度。比如函数f(x,y), 分别对x,y求偏导数,求得的梯度向量就是(∂f/∂x, ∂f/∂y)T,简称grad f(x,y)或者▽f(x,y)。对于在点(x0,y0)的具体梯度向量就是(∂f/∂x0, ∂f/∂y0)T.或者▽f(x0,y0),如果是3个参数的向量梯度,就是(∂f/∂x, ∂f/∂y,∂f/∂z)T,以此类推。

  那么这个梯度向量求出来有什么意义呢?他的意义从几何意义上讲,就是函数变化增加最快的地方。具体来说,对于函数f(x,y),在点(x0,y0),沿着梯度向量的方向就是(∂f/∂x0, ∂f/∂y0)T的方向是f(x,y)增加最快的地方。或者说,沿着梯度向量的方向,更加容易找到函数的最大值。反过来说,沿着梯度向量相反的方向,也就是 -(∂f/∂x0, ∂f/∂y0)T的方向,梯度减少最快,也就是更加容易找到函数的最小值。

导数可以代表J 增大的方向,如上图一点导数为负值,说明J增大的方向是沿着X轴负方向。此时需要向右移动

    当导数为0时损失函数的最小。

由上图可知想要最快取到最优解,那么第一个点的取值较为重要,此时有点看运气。    

线性回归中使用梯度下降法

小括号第一个值是准确的结果,第二个值是所训练模型的输出值。

模拟梯度下降法

"""模拟梯度下降法"""

import numpy as np

import matplotlib.pyplot as plt

plot_x = np.linspace(-1, 6, 141)

plot_y = (plot_x - 2.5) ** 2 - 1

plt.plot(plot_x, plot_y)

plt.show()

def dJ(theta):

    """计算导数值"""

    return 2 * (theta - 2.5)

def J(theta):

    """计算损失函数的值"""

    return (theta - 2.5) ** 2 - 1

theta = 0.0

theta_history = [theta]

def gradient_descent(initial_theta,eta,epsilon=1e-8):

    """模拟梯度下降法"""

    theta=initial_theta

    theta_history.append(initial_theta)

    while True:

        gradient = dJ(theta)

        last_theat = theta

        theta = theta - eta * gradient

        theta_history.append(theta)

        if abs(J(theta)-J(last_theat)) < epsilon:

            break

def plot_theta_history():

    plt.plot(plot_x,J(plot_x))

    plt.plot(np.array(theta_history),J(np.array(theta_history)),color='r')

    plt.show()

eta = 0.8

theta_history=[]

gradient_descent(0.,eta)

plot_theta_history()

如果参数过多,那么需要对每个参数求偏导,然后移动位置,使得损失函数的值尽可能的小。

将w和b对L的两个偏微分所得到的结果排成一vector,这个vector 就叫做gradient。那么倒三角L就是所有参数对L 的偏微分形成的vector。

例如有两个参数(w,b),下图的颜色代表Loss 的值,假设起始点从第一个红点开始,经过几次指向移动到loss值最小的地方。

偏微分计算的例子:

def fit_gd(self, X_train, y_train, eta=0.01, n_iters=1e4):

        """根据训练数据集X_train, y_train, 使用梯度下降法训练Linear Regression模型"""

        assert X_train.shape[0] == y_train.shape[0], \

            "the size of X_train must be equal to the size of y_train"

        def J(theta, X_b, y):

            """求损失函数"""

            try:

                return np.sum((y - X_b.dot(theta)) ** 2) / len(y)

            except:

                return float('inf')

        def dJ(theta, X_b, y):

            """求梯度"""

            # res = np.empty(len(theta))

            # res[0] = np.sum(X_b.dot(theta) - y)

            # for i in range(1, len(theta)):

            #     res[i] = (X_b.dot(theta) - y).dot(X_b[:, i])

            # return res * 2 / len(X_b)

            return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(X_b)

        def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):

            theta = initial_theta

            cur_iter = 0

            while cur_iter < n_iters:

                gradient = dJ(theta, X_b, y)

                last_theta = theta

                theta = theta - eta * gradient

                if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):

                    break

                cur_iter += 1

            return theta

        X_b = np.hstack([np.ones((len(X_train), 1)), X_train])

        initial_theta = np.zeros(X_b.shape[1])

        self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters)

        self.intercept_ = self._theta[0]

        self.coef_ = self._theta[1:]

        return self
发布了34 篇原创文章 · 获赞 45 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/one_super_dreamer/article/details/102685771