最近,训练过程中遇到了一些问题,所有回头看了一些原理性的内容,学习过程做了简单记录,如果有不准确的点,欢迎大家指正。
梯度下降(gradient descent)
梯度下降法的基本思想可以类比为一个下山的过程。假设这样一个场景:一个人被困在山上,需要从山上下来(i.e. 找到山的最低点,也就是山谷)。但此时山上的浓雾很大,导致可视度很低。因此,下山的路径就无法确定,他必须利用自己周围的信息去找到下山的路径。这个时候,他就可以利用梯度下降算法来帮助自己下山。具体来说就是,以他当前的所处的位置为基准,寻找这个位置最陡峭的地方,然后朝着山的高度下降的地方走,同理,如果我们的目标是上山,也就是爬到山顶,那么此时应该是朝着最陡峭的方向往上走。然后每走一段距离,都反复采用同一个方法,最后就能成功的抵达山谷。
Cost function (loss function, objective function): 目标函数
- C: cost
- w: weight 权重
- b: bias 偏向
- n: 训练数据集实例个数
- x: 输入值
- a: 输出值 (当x是输入时)
- ||v||: 向量的length function
C(w,b) 越小越好,输出的预测值和真实值差别越小,因此我们在训练过程的目标是最小化C(w,b)
最小化问题可以用梯度下降解决(gradient descent),假设目标函数C有两个参数v1和v2,通常可以用微积分解决,如果v包含的变量过多,无法用微积分解决.
对于一个变量,我们可以抽象成一个小球在曲面上的某一点,滚动到最低点,假设y在mininum的右侧,每点的导数>0 ,假设每次移动 ,结果仍然>0 ,其中代表学习率(每次我们移动的步长),当y在mininum左侧 结果仍然大于0,仍然向下移动。
梯度下降的特点
1、可能会陷入局部最优 2、前提是目标函数要是凸函数convex 3、learning rate自动会减小
对于多个变量,每个变量的更新方法如下
推导过程:
1,总的cost方程变化量和各个变量偏导方向的变化和大概相同
2,我们假设
3,多个对於单个变量 梯度指这个变量的导数,对于多个变量 梯度只多个变量组成向量的转置如下
可以推出
4,由前面的单变量,我们假设
可以推出: <=0
所以对于变量,可以使目标函数逐渐降低。
5,对于平均cost函数 可以推出
== >
==>
随机梯度下降算法(stochastic gradient descent)
对于一个训练过程,一般实例都有几万或者几十万,对于人脸项目都有数百万的训练集,如果等都训练一遍在更新不太现实。
基本思想:从所有训练实例中随机取一个采样(sample):X1,X2,...,Xm (mini-batch),来估计▽T,大大提高学习效率。
可以推断出
w和b的更新方程如下:
然后重新选择下一个mini_batch 进行训练。
代码实现如下:
def SGD(self,train_data,epoches,mini_size,eta,test_data):
if test_data: n_test = len(test_data)
n = len(train_data) #表示 训练样本数量
for epoch in range(epoches):
random.shuffle(train_data)
mini_batches = [train_data[k:k+mini_size] for k in xrange(0,n,mini_size)] #xrange 返回的是生成器
for mini_batch in mini_batches:
self.update_minibatch(mini_batch,eta)
if test_data:
print "epoches {0} acc {1}/{2} ".format(epoch,self.cal_acc(test_data),n_test)
else:
print "no test data"
# mini_batch 代表mini_size 个元组(x,y) 其中x是输入的维度 ,输出是class的种类
def update_minibatch(self,mini_batch,eta):
nabla_b = [np.zeros(b.shape) for b in self.biases] #随机梯度下降算法,用于存储我们指定的minibatch中的数据的bias的总和
nabla_w = [np.zeros(w.shape) for w in self.weights]
for x,y in mini_batch:
new_nabla_b ,new_nabla_w = self.back(x,y)
nabla_w = [nw+w for nw,w in zip(new_nabla_w,nabla_w)]
nabla_b = [nb+b for nb,b in zip(new_nabla_b,nabla_b)]
self.weights = [w-((eta/len(mini_batch))*nabla_w) for w,nabla_w in zip(self.weights,nabla_w)]
self.biases = [b-((eta/len(mini_batch))*nabla_b) for b,nabla_b in zip(self.biases,nabla_b)]