cs231n_optimization_note

cs231n课程源网页 点击打开链接

记录一下看教程过程中的自己的一些想法(顺便吐槽一下这个编辑器写公式好像有点疼,以后考虑用markdown),仅写一下一些自认为较为难理解的部分,跳过了很多较简单的内容......


图片分类任务主要分为两个过程,首先得到一个得分方程,即将一张图片利用一些函数(Linear、MLP或者神经网络都是在做这个事)得出其对所有类别的得分,而要怎么评价一个这样的函数的好坏以便我们改进我们的模型,则需要定义一个损失函数(loss function),这也有很多方式,例如利用Softmax将所有分数归一化,转化为一个概率,或者利用SVM计算真实标记与计算类别之间的差值,这里较简单,可以看cs231n的前一节......

如何最优化我们建立的模型这就是优化的问题,例如在Linear model中找到最优的W,使得loss最小。

由于W维度较高,要使loss function可视化,可以通过固定W的某些维度进行,这个与二维空间其实类似,例如在二维空间中有一点Wi(xi, yi),通过计算L(W+aWi)的值与a的关系,就可以获取L在Wi轴上的变化情况。在二维空间中就相当于在由(0, 0)与(xi, yi)决定的直线上L的变化情况,加上其他维度类似这一过程(二维平面,三维空间......),所以利用loss function L(W + aW1 + bW2),就可以通过a与b的变化得到不同的loss值,便可以可视化loss function在W1和W2组成的平面上的变化情况。


图引自cs231n课程网站, 第一幅图是只使用一个W1得到的。

optimization有三种方法,随机搜索(每次使用新的W以及加入一个δW)以及梯度下降方法,前两种比较简单

在计算梯度的方法中,有两种方式计算梯度,数值梯度(numerical gradient)和解析梯度(analytic gradient)

数值梯度(numerical gradient

课程网页上面写了一种比较simple、naive的方式,其实也就是对每个维度,加上一个较小的数,求函数值,然后利用导数的定义近似计算,即利用下式计算


这种方法计算较为精确,但是如果x的维度(a)特别特别大的话每次计算梯度就要花费大量的时间(o(a)时间复杂度)......

代码如下所示:

def eval_numerical_gradient(f, x):
  """ 
  a naive implementation of numerical gradient of f at x 
  - f should be a function that takes a single argument
  - x is the point (numpy array) to evaluate the gradient at
  """ 

  fx = f(x) # evaluate function value at original point
  grad = np.zeros(x.shape)
  h = 0.00001

  # iterate over all indexes in x
  it = np.nditer(x, flags=['multi_index'], op_flags=['readwrite']) # 对x的所有元素进行迭代
  while not it.finished:

    # evaluate function at x+h
    ix = it.multi_index
    old_value = x[ix]
    x[ix] = old_value + h # increment by h
    fxh = f(x) # evalute f(x + h)
    x[ix] = old_value # restore to previous value (very important!)

    # compute the partial derivative
    grad[ix] = (fxh - fx) / h # the slope
    it.iternext() # step to next dimension

  return grad

在实际中使用|f(x+h)-f(x-h)|/2h更多一些,利用计算的梯度可以进行W的更新,W = W - step_size * df,这里使用负方向,表示沿loss变小的方向,这里的step_size就是神经网络中常用的一个超参,这个步长对训练影响很大。步长太大可能导致无法收敛,步长太小则速度太慢。

解析梯度(analytic gradient)

其实也就是数学上的求导数(多变量求偏导),然后可以直接代入得到一个点的梯度值,但是这种方式容易出错,所以就引入了梯度检查(gradient check)来对比解析梯度和数值梯度的值。

例如SVM的loss function如下:


其对wyi的偏导数为:


其实很好理解,L是由多个max函数组成,而每个max函数是一个hinge函数,max()函数的后部分对于某一个w而言,就是一个线性关系,即wj * xi - wyi * xi + delta = wyi * a + b, wyi为变量,a和b是参数,所以其导数在后面一项小于0时是0,在其大于零时导数为a(也即是xi)

对于j不等于yi的情况,wj的偏导数是:



梯度下降(Gradient Descent)

梯度下降就是各种NN中使用较多的优化器了,也就是沿负梯度方向使loss值减小,代码如下:

while True:
  weights_grad = evaluate_gradient(loss_fun, data, weights)
  weights += - step_size * weights_grad # perform parameter update
回顾一下可以发现,这整个optimization的过程,其实涉及到对所有训练集的计算(对每个训练集都能得到一个loss值,而最终的loss是所有训练集loss的均值)然后求出梯度进行更新,一步就需要花费很多时间,所以一般利用mini-batch,每次利用一小批数据进行更新,加快训练速度,随机梯度下降(Stochastic Gradient Descent ,SGD)是比较特殊的,其mini-batch为1, 而如何选择mini-batch这个一般由我们的内存决定(例如32、64、128 and so on)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值