首页 > 代码库 > Theano深度学习(一)---- 安装与使用

Theano深度学习(一)---- 安装与使用

/* Author: cyh_24 */

/* Date: 2014.10.2 */

/* Email: cyh@buaa.edu.cn */

/* More: http://blog.csdn.net/cyh_24 */

最近,研究的关注点在以图搜图 这块,近期这块内容的比赛较多,为了不拖师兄的后腿太多,决定潜心研究DeepLearning,主要以Theano官方教程Deep Learning Tutorial为参考。

这个系列的博客应该会持续更新,希望大家多多指点,共同学习!

转载请注明:http://blog.csdn.net/cyh_24/article/details/41827691

1. 下载代码与数据

Theano官方提供了学习用的全部代码和数据集

你可以从githubclone下来:

git clone git://github.com/lisa-lab/DeepLearningTutorials.git

2. 数据集的使用

2.1 MNIST DataSet

(mnist.pkl.gz)
mnist 数据集由手写数字图像组成,分成60,000个训练样本和10,000测试样本。
在许多论文,与这个教程一样,官方的60,000训练样本分成50,000个训练样本和10,000个验证样本
验证样本:用于选择像学习率和模型大小的超参数)
所有手写数字图像大小都归一化在固定的28*28大小的灰度图像中。

这里有一些MNIST手写数字的例子:

2.2 使用数据集

你可以通过下面的代码进行导入数据:
import cPickle, gzip, numpy
# Load the dataset
f = gzip.open(’mnist.pkl.gz’, ’rb’)
train_set, valid_set, test_set = cPickle.load(f)
f.close()


值得注意的是,当我们使用这些数据集的时候,我们通常是把它们分成多个小块(称为minibatcheds)。并且,官方建议我们在读入数据之后,应该把数据存储到共享变量(shared variables)中。使用共享变量的理由与使用GPU有关。当拷贝数据到GPU内存时,从CPU拷贝数据到GPU是个大的效率瓶颈。当代码要做拷贝数据,如果没有使用共享变量,因为这个瓶颈,GPU代码不会比CPU代码快(甚至可能更慢)。

使用共享变量的方法如下:
def shared_dataset(data_xy):
    data_x, data_y = data_xy
    shared_x = theano.shared(numpy.asarray(data_x, dtype=theano.config.floatX))
    shared_y = theano.shared(numpy.asarray(data_y, dtype=theano.config.floatX))

    return shared_x, T.cast(shared_y, ’int32’)

#使用共享变量
test_set_x, test_set_y = shared_dataset(test_set)
valid_set_x, valid_set_y = shared_dataset(valid_set)
train_set_x, train_set_y = shared_dataset(train_set)
batch_size = 500 # size of the minibatch
# accessing the third minibatch of the training set
data = http://www.mamicode.com/train_set_x[2 * 500: 3 * 500]>

注意:

  1. 如果你在GPU上运行,使用的数据集超出内存的大小,代码会崩溃。这种情况下,需要把数据保存到共享变量。
  2. 在训练数据的时候,你可以保存为足够小的数据块到共享变量。一旦你通过数据块获取数据,需要保存更新的值。
  3. 这个方法能够使CPU和GPU内存之间的数据传输效率最大化。

3. 约定的名称

3.1 数据集名词

分别代表训练集、验证集、测试集。

对于每个数据集,由数据x跟标签y组成:

3.2 数学定义

3.3 符号跟缩略语

4. DeepLearning的监督学习入门

Deep Learning 最令人兴奋的一点事它使用大量的非监督式来学习神经网络。但是,监督式学习仍然在其中扮演了重要的角色。一般来说,无监督学习到的东西,在监督学习的微调之后能够达到更好的效果。这节的监督学习入门主要介绍一下几个方面:

  1. 简单介绍监督学习在分类模型中的作用
  2. 介绍 批量随机梯度下降算法

4.1 学习一个分类器

4.1.1 Zero-One Loss

训练分类器的目的是将分类的错误(Zero-One Loss)尽可能减小。

如果预测函数 是:

那么它的错误代价 就是:

在这里,D是训练集,I 的意义如下:

当x为True的时候,它为1;否则为0

在本教程中,f(预测函数) 定义如下:

我们可以用Theano来写出上面的代码:

zero_one_loss = T.sum(T.neq(T.argmax(p_y_given_x), y))

4.1.2 Log-Likelihood Loss(负对数似然代价函数)

因为Zero-One Loss是非可微分的,为了在大模型(成千上万的参数)中优化它,计算量相当惊人。因此,我们用Log-Likelihood Loss来代替:

同样,也是通过最小化这个似然函数来得到优化,最小化的过程我们成为NLL(negative log-likelihood),如下:

同样,用Theano写出的代码仍然很简单:

NLL = -T.sum(T.log(p_y_given_x)[T.arange(y.shape[0]), y])

4.2 Stochastic Gradient Descent (随机梯度下降)

普通的梯度下降法
梯度下降法,就是利用负梯度方向来决定每次迭代的新的搜索方向,使得每次迭代能使待优化的目标函数逐步减小。

普通梯度下降法的伪代码

# GRADIENT DESCENT
while True:
    loss = f(params)
    d_loss_wrt_params = ... # compute gradient
    params -= learning_rate * d_loss_wrt_params
    if <stopping condition is met>:
    return params

随机梯度下降法
随机梯度下降是每次通过一个样本(而不是整个训练集)来迭代更新一次,如果样本量很大的情况(例如几十万),那么可能只用其中几万条或者几千条的样本,就已经将theta迭代到最优解了。

但是,SGD伴随的一个问题是噪音较多,使得SGD并不是每次迭代都向着整体最优化方向。

SGD伪代码如下

# STOCHASTIC GRADIENT DESCENT
for (x_i,y_i) in training_set:
    # imagine an infinite generator
    # that may repeat examples (if there is only a finite training loss = f(params, x_i, y_i)
    d_loss_wrt_params = ... # compute gradient  
    params -= learning_rate * d_loss_wrt_params
    if <stopping condition is met>:
    return params

批量随机下降法
Theano深度学习教材中推荐的是随机梯度下降的一个优化的变种,叫做批量随机下降(Minibatch SGD)。批量随机下降的基本工作原理跟随机下降一样,只是,每次使用了更多的训练样本来估计梯度。 这有效的减少了估计梯度的方差,同时更好地利用了计算机内存。

MSGD伪代码如下:

for (x_batch,y_batch) in train_batches:
    # imagine an infinite generator
    # that may repeat examples
    loss = f(params, x_batch, y_batch)
    d_loss_wrt_params = ... # compute gradient using theano
    params -= learning_rate * d_loss_wrt_params
    if <stopping condition is met>:
        return params

注意:
在这里,批的大小B是一个权衡的选择,需要考虑模型、数据集、硬件等;文本选择的是20,当然你可以任意选取(不会对结果正确性些有影响)。
但是,如果你的训练次数是固定的,那么批的大小将会对结果产生影响。

下面,我们用Theano写出一个完整的MSGD:

# Minibatch Stochastic Gradient Descent
# assume loss is a symbolic description of the loss function given
# the symbolic variables params (shared variable), x_batch, y_batch;
# compute gradient of loss with respect to params
d_loss_wrt_params = T.grad(loss, params)
# compile the MSGD step into a theano function
updates = [(params, params - learning_rate * d_loss_wrt_params)]
MSGD = theano.function([x_batch,y_batch], loss, updates=updates)
for (x_batch, y_batch) in train_batches:
    # here x_batch and y_batch are elements of train_batches and
    # therefore numpy arrays; function MSGD also updates the params
    print(’Current loss is ’, MSGD(x_batch, y_batch))
    if stopping_condition_is_met:
        return params

4.3 规则化

批量随机梯度下降是一个线性更新的算法,可以使用新的样本来训练已有的模型。这方便,但是会出现一种过拟合的可能。为了防止过拟合的出现,我们可以使用两个方法:

  1. 规则化的方法;
  2. 训练到一定时间提早结束;

4.3.1 规则化

L1和L2的规则化方法是通过向代价函数中增加一个新的惩罚项,用来惩罚一些参数配置(规则化也叫做权值衰减)
一般情况下,如果我们的代价函数如下:

那么,经过规则化后的代价函数就是:

我们的例子中,规则化后的代价函数式:

原则上,当添加一个规则化到代价函数中,会使得神经网络的映射更加平滑(通过惩罚值大的参数,这将减少网络模型的非线性)。

看看python中的实现:

# symbolic Theano variable that represents the L1 regularization term
L1 = T.sum(abs(param))
# symbolic Theano variable that represents the squared L2 term
L2_sqr = T.sum(param ** 2)
# the loss
loss = NLL + lambda_1 * L1 + lambda_2 * L2

4.3.2 提早结束

验证集: 没有被用于梯度下降训练,也不是测试集的一部分。可以认为它是测试的代表。

我们可以通过验证集来验证模型的性能,来判断是否出现过拟合的情况。如果模型的性能在验证集中没有明显的提升,或者甚至下降了,那么我们应该停止继续迭代。

5 介绍语

python 这么优雅,Theano 这么‘库’,deep-learning 这么潮,不多说了,我也提早结束吧......

Theano深度学习(一)---- 安装与使用