美文网首页程序员Python数据科学
深度学习入门--随机梯度下降法

深度学习入门--随机梯度下降法

作者: 爱吃西瓜的番茄酱 | 来源:发表于2019-03-27 16:54 被阅读2次

    数值微分就是利用数值方法近似求解函数的导数的方法。根据大一学习的【高等数学】的知识可知,函数的导数近似等于函数的差值除以自变量的差值,当自变量的差值趋近于无穷小时。

    用Python表示如下:

    def numerical_diff(f, x):
        h=1e-4  # 0.0001
        return (f(x+h)-f(x-h))/(2*h)
    

    为了保证这个微小的差分不被Python解释器直接省略,所以这里采用中心差分的形式(f(x+h)-f(x-h))/(2*h)

    用数值微分举个例子:

    def function_1(x):
        return 0.01*x**2 + 0.1*x
    
    #计算function_1(5)的数值微分
    print(numerical_diff(function_1, 5))
    

    结果:

    0.1999999999990898
    

    可以看出计算结果和真实结果0.2的误差已经非常小了,可以近似认为它们两者相等。

    偏导数

    有多个变量的函数的导数称为偏导数。求一个变量的偏导数,就是先将其他变量当做常数,再对函数求导。

    梯度

    由全部变量的偏导数汇总而成的向量称为梯度。

    用Python实现如下:

    def numerical_gradient(f, x):
        h=1e-4  # 0.0001
        grad=np.zeros_like(x) # 生成和x形状相同的数组
        
        for i in range(x.size):
            t=x[i]
            # f(x+h)的计算
            x[i]=t+h
            f_h1=f(x)
            
            # f(x-h)的计算
            x[i]=t-h
            f_h2=f(x)
            
            grad[i]=(f_h1-f_h2)/(2*h)
            x[i]=t  # 还原值
            
        return grad
    

    函数numerical_gradient(f, x)中,参数f为多元函数,参数x为numpy数组。

    梯度是一个向量,这个向量指示的方向是各点处的函数值减小最多的方向。

    梯度法

    机器学习的主要任务是在学习时寻找最优参数,这个最优参数是指是损失函数取最小值的参数。而通过使用梯度来寻找损失函数最小值(或者说尽可能小的值)的方法称为梯度法。

    寻找最小值的梯度法称为梯度下降法,一般而言,在神经网络中,梯度法主要是指梯度下降法。

    用Python实现梯度下降法:

    def gradient_descent(f, init_x, lr=0.1, step_num=100):
        x=init_x
        
        for i in range(step_num):
            grad=numerical_gradient(f, x)
            x -= lr*grad
            
        return x
    

    参数f是要进行优化的函数,init_x是初始值,lr是学习率,step_num是梯度法重复的次数。

    像学习率这样的参数称为超参数,这是和权重、偏置都不同的参数,权重和偏置可以通过训练学习自动获得,而学习率这样的超参数只能人工设定。由于是人工设定,所以必须多尝试几个值,以便达到较好的效果。

    两层神经网络的类

    先实现一个名为TwolayerNet的神经网络,再利用这个网络的实例进行随机梯度下降法的学习。

    import os, sys
    sys.path.append(os.pardir)
    from common.funciton import *
    from common.gradient import numerical_gradient
    import numpy as np
    
    class TwolayerNet:
        
        def __init__(self, input_size, hidden_size, output_size, weight_init_std=0.01):
            # 初始化权重
            self.params={}
            self.params['w1']=weight_init_std * np.random.randn(input_size, hidden_size)
            self.params["b1"]=np.zeros(hidden_size)
            self.params['w2']=weight_init_std * np.random.randn(hidden_size, output_size)
            self.params['b2']=np.zeros(output_size)
            
        def predict(self, x):
            w1, w2=self.params['w1'], self.params['w2']
            b1, b2=self.params['b1'], self.params['b2']
            
            a1=np.dot(x, w1) + b1
            z1=sigmoid(a1)
            a2=np.dot(z1, w2) + b2
            y=softmax(a2)
            
            return y
        
        # x:输入数据, t:监督数据
        def loss(self, x, t):
            y=self.predict(x)
            
            return cross_entropy_error(y,t)  # 交叉熵误差
        
        def accuracy(self, x, t):
            y=self.predict(x)
            y=np.argmax(y, axis=1)
            t=np.argmax(t, axis=1)
            
            accuracy=np.sum(y==t)/float(x.shape[0])
            return accuracy
        
        # x:输入数据, t:监督数据
        def numerical_gradient(self, x, t):
            loss_w = lambda w : self.loss(x, t)
            
            grads={}
            grads['w1']=numerical_gradient(loss_w, self.params['w1'])
            grads['b1']=numerical_gradient(loss_w, self.params['b1'])
            grads['w2']=numerical_gradient(loss_w, self.params['w2'])
            grads['b2']=numerical_gradient(loss_w, self.params['b2'])
            
            return grads
    

    神经网络的学习

    神经网络的学习的实现使用的是mini-batch学习。即是从训练数据中随机选择一部分数据(称为mini-batch),再以这些mini-batch为对象,使用随机梯度下降法更新参数的过程。

    接下来以TwolayerNet类为对象,使用MNIST数据集进行学习。

    import os, sys
    sys.path.append(os.pardir)
    import numpy as np
    from dataset.mnist import load_mnist
    from two_layer_net import TwoLayerNet
    
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, one_hot_label=True)
    
    train_loss_list=[]
    
    # 超参数
    iters_num=1000  # 梯度法更新次数
    train_size=x_train.shape[0]
    batch_size=100  # 每个mini-batch的大小
    learning_rate=0.1  # 学习率
    
    network=TwoLayerNet(input_size=784, hidden_size=50, output_size=10)
    
    
    for i in range(iters_num):
        # 获取mini-batch
        batch_mask=np.random.choice(train_size, batch_size)
        x_batch=x_train[batch_mask]
        t_batch=t_train[batch_mask]
        
        # 计算梯度
        grad=network.numerical_gradient(x_batch, t_batch)
        # grad=network.gradient(x_batch, t_batch) # 高速版
        
        # 更新参数
        for key in ('W1', 'b1', 'W2', 'b2'):
            network.params[key] -= learning_rate * grad[key]
            
        # 记录学习过程
        loss=network.loss(x_batch, t_batch)
        train_loss_list.append(loss)
    

    学习的过程会花费较长的时间,电脑配置太低了就很难受。

    每天学习一点点,每天进步一点点。

    相关文章

      网友评论

        本文标题:深度学习入门--随机梯度下降法

        本文链接:https://www.haomeiwen.com/subject/hdravqtx.html