神经网络的梯度下降算法实现

首先我们需要确定一点的是什么是梯度法,我们为什么需要使用它,通过梯度下降能给我们带来什么?

首先我们的梯度下降算法是对损失函数用的,对损失函数使用梯度下降就是神经网络的反向传播,通过对损失函数求最小值得到的W和b就是最适合我们神经网络的W和b。

机器学习的主要任务是在学习时寻找最优参数。同样地,神经网络也必须在学习时找到最优参数(权重和偏置)。这里所说的最优参数是指损失函数。损失函数取最小值时的参数。但是,一般而言,损失函数很复杂,参数空间庞大,我们不知道它在何处能取得最小值。而通过巧妙地使用梯度来寻找函数最小值(或者尽可能小的值)的方法就是梯度法。

在梯度法中,函数的取值从当前位置沿着梯度方向前进一定距离,然后在新的地方重新求梯度,再沿着新梯度方向前进,如此反复,不断地沿梯度方向前进。像这样,通过不断地沿梯度方向前进,逐渐减小函数值的过程就是梯度法(gradient method)。梯度法是解决机器学习中最优化问题的常用方法,特别是在神经网络的学习中经常被使用。根据目的是寻找最小值还是最大值,梯度法的叫法有所不同。严格地讲,寻找最小值的梯度法称为梯度下降法(gradient descent method),寻找最大值的梯度法称为梯度上升法(gradient ascent method)。但是通过反转损失函数的符号,求最小值的问题和求最大值的问题会变成相同的问题,因此“下降”还是“上升”的差异本质上并不重要。一般来说,神经网络(深度学习)中,梯度法主要是指梯度下降法。

梯度表示:

首先我们先来实现求梯度

#梯度实现
import numpy as np
def function_2(x):
    return x[0]**2+x[1]**2

def numerical_gradient(f,x):
    h=1e-4 #0.0001
    grad=np.zeros_like(x) #生成与x形状相同的数组
    for idx in range(x.size): #如X[3,4],idx=0,1
        tmp_val=x[idx]
        x[idx]=tmp_val+h #f(x+h)的计算
        fxh1=f(x)
        x[idx]=tmp_val-h #f(x-h)的计算
        fxh2=f(x)
        grad[idx]=(fxh1-fxh2)/(2*h) #梯度计算
        x[idx]=tmp_val #还原x为[3,4]
    return grad

print(numerical_gradient(function_2,np.array([3.0,4.0])))#[6. 8.]

接下来我们来实现完整的梯度下降算法

#梯度下降
import numpy as np
def function_2(x):
    return x[0]**2+x[1]**2

def numerical_gradient(f,x):
    h=1e-4 #0.0001
    grad=np.zeros_like(x) #生成和x形状相同的数组
    for idx in range(x.size):
        tmp_val=x[idx]
        x[idx]=tmp_val+h #f(x+h)
        fxh1=f(x)
        x[idx]=tmp_val-h #f(x-h)
        fxh2=f(x)
        grad[idx]=(fxh1-fxh2)/(2*h) #梯度计算
        x[idx]=tmp_val #还原x为[3,4]
    return grad

def gradient_descent(f,init_x,lr=0.01,step_num=200):
    x=init_x
    for i in range(step_num):
        grad=numerical_gradient(f,x)
        x-=lr*grad #这里因为是梯度下降算法所以需要加负号,如果是梯度上升算法则可以将负号去掉。
    return x

print(gradient_descent(function_2,np.array([-3.0,4.0])))#[-0.05276384  0.07035179]
print(gradient_descent(function_2,np.array([-3.0,4.0]),lr=10))#[-2.58983747e+13 -1.29524862e+12]
print(gradient_descent(function_2,np.array([-3.0,4.0]),lr=1e-4))#[-2.88235679  3.84314238]
#注意,梯度下降算法求得是函数最小值,而我们代码输出的结果例如第一个的第一个输出结果是-0.05276384即为function_2函数中当x=-3.0时函数可以取到的最小值

如果目标函数本身不是一个凸函数,那么梯度下降大概率将收敛于目标函数的局部最小值(步长跨过了函数最小值点,即在梯度下降没有在最小值点得到梯度。在工程实践中,一般都是收敛于局部最小值) ,当然也可能收敛于全局最小值(步长没有影响到最小值的梯度,即在一定步长下,梯度下降在最小值点取到了极值,也就是真正的最小值)。造成局部最小的主原因在于步长α,步长过大,则会错过全局极小值(也就是最终的全局最小值),步长过小,则会导致大量训练冗余。这里的步长就是学习率,也就是代码中的lr

接下来我们进入神经网络的梯度下降算法实现

#神经网络的梯度实现
import os
import sys
import numpy as np
sys.path.append(os.pardir)

def softmax(a): #用来处理经过神经网络处理后的数据,对数据进行分类
    c=np.max(a)
    exp_a=np.exp(a-c) #防止溢出
    sum_exp_a=np.sum(exp_a)
    y=exp_a/sum_exp_a
    return y

def cross_entropy_error(y,t):#损失函数,用来处理神经网络中的优化问题
    if y.ndim==1:
        t=t.reshape(1,t.size)
        y=y.reshape(1,y.size)
    batch_size=y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size),t]+1e-7))

def numerical_gradient(f,x):
    h=1e-4 #0.0001
    grad=np.zeros_like(x) #生成和x形状相同的数组
    for idx in range(x.size):
        tmp_val=x[idx]
        x[idx]=tmp_val+h #f(x+h)
        fxh1=f(x)
        x[idx]=tmp_val-h #f(x-h)
        fxh2=f(x)
        grad[idx]=(fxh1-fxh2)/(2*h) #梯度计算
        x[idx]=tmp_val #还原x为[3,4]
    return grad

def numercial_gradient_2d(f,x):
    if x.ndim==1:
        return numerical_gradient(f,x)
    else:
        grad=np.zeros_like(x)
        for idx,x in enumerate(x):
            grad[idx]=numerical_gradient(f,x)
    return grad

class simple:
    def __init__(self):
        self.W=np.random.randn(2,3) #用高斯分布进行初始化
    def predict(self,x):
        return np.dot(x,self.W)
    def loss(self,x,t):
        z=self.predict(x)
        y=softmax(z)
        loss=cross_entropy_error(y,t)
        return loss

net=simple()
x=np.array([0.6,0.9])
t=np.array([0,0,1])#正确解标签

f=lambda w:net.loss(x,t)
dw=numercial_gradient_2d(f,net.W)
print(dw)
'''
[[ 0.21335744 -0.41012739  0.19676996]
 [ 0.32003616 -0.61519109  0.29515493]]
'''

这里我们需要建立一个simple的类,为什么要建立一个类呢?我们要求L和W的梯度,而我们的损失函数与x和t相关,t是正确解标签,是常数,所以问题在于怎样将w与x联系起来。所以建立一个类,求损失函数时,w改变x随之改变。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值