大部分深度学习框架的tutorial都是从多层感知器开始参考的,所以今天学习了一下torch7的MLP。
第一部分:参数的设定。torch的参数设定并不同于caffe,caffe使用google的protobuf来当作参数的传递的,而这里用的是cmd:opt( "--参数",“参数的可选数值","参数的描述")。这样,在设定玩参数之后,只需用解析参数,在进行适当的数值转化就可以使用啦,这些初始化的参数可以被两个方法callBack和epoch_callBack每次的调用进行适当的修改就可以进行运行啦。同时我们也可以使用参数--silent参数来设定是否要打印这些参数opt项。
-- dp是深度学习的依赖包 require 'dp' --[[command line arguments]]-- cmd = torch.CmdLine() cmd:text() cmd:text('Image Classification using MLP Training/Optimization') cmd:text('Example:') cmd:text('$> th neuralnetwork.lua --batchSize 128 --momentum 0.5') cmd:text('Options:') -- 学习率以及衰减系数相关的控制参数 cmd:option('--learningRate', 0.1, 'learning rate at t=0') cmd:option('--lrDecay', 'linear', 'type of learning rate decay : adaptive | linear | schedule | none') cmd:option('--minLR', 0.00001, 'minimum learning rate') cmd:option('--saturateEpoch', 300, 'epoch at which linear decayed LR will reach minLR') cmd:option('--schedule', '{}', 'learning rate schedule') cmd:option('--maxWait', 4, 'maximum number of epochs to wait for a new minima to be found. After that, the learning rate is decayed by decayFactor.') cmd:option('--decayFactor', 0.001, 'factor by which learning rate is decayed for adaptive decay.') cmd:option('--maxOutNorm', 1, 'max norm each layers output neuron weights') cmd:option('--momentum', 0, 'momentum') -- 激活函数,隐藏神经元个数,每次训练的个数 cmd:option('--activation', 'Tanh', 'transfer function like ReLU, Tanh, Sigmoid') cmd:option('--hiddenSize', '{200,200}', 'number of hidden units per layer') cmd:option('--batchSize', 32, 'number of examples per batch') -- 硬件相关的参数GPU cmd:option('--cuda', false, 'use CUDA') cmd:option('--useDevice', 1, 'sets the device (GPU) to use') cmd:option('--maxEpoch', 100, 'maximum number of epochs to run') cmd:option('--maxTries', 30, 'maximum number of epochs to try to find a better local minima for early-stopping') -- 是否使用dropout方法解决过拟合和batchNorm cmd:option('--dropout', false, 'apply dropout on hidden neurons') cmd:option('--batchNorm', false, 'use batch normalization. dropout is mostly redundant with this') -- 数据集的选取以及相关的标准化方法 cmd:option('--dataset', 'Mnist', 'which dataset to use : Mnist | NotMnist | Cifar10 | Cifar100') cmd:option('--standardize', false, 'apply Standardize preprocessing') cmd:option('--zca', false, 'apply Zero-Component Analysis whitening') cmd:option('--lecunlcn', false, 'apply Yann LeCun Local Contrast Normalization') -- 是否打印进度条和相关的opt参数 cmd:option('--progress', false, 'display progress bar') cmd:option('--silent', false, 'dont print anything to stdout') cmd:text() -- 解析参数 opt = cmd:parse(arg or {}) opt.schedule = dp.returnString(opt.schedule) opt.hiddenSize = dp.returnString(opt.hiddenSize) if not opt.silent then table.print(opt)-- 是否打印相关的opt end
这部分是和数据源选取相关的代码,根据前面的相关的参数opt种的--dataset选取相对应的参数。都是熟悉的经典数据集。用dataset(ds)来代表数据集。
if opt.dataset == 'Mnist' then ds = dp.Mnist{input_preprocess = input_preprocess} elseif opt.dataset == 'NotMnist' then ds = dp.NotMnist{input_preprocess = input_preprocess} elseif opt.dataset == 'Cifar10' then ds = dp.Cifar10{input_preprocess = input_preprocess} elseif opt.dataset == 'Cifar100' then ds = dp.Cifar100{input_preprocess = input_preprocess} elseif opt.dataset == 'FaceDetection' then ds = dp.FaceDetection{input_preprocess = input_preprocess} else error("Unknown Dataset") end
下面当然是数据的标准化处理,这里我们熟悉的就是--standardize参数。我们用input_process存放。
local input_preprocess = {} if opt.standardize then table.insert(input_preprocess, dp.Standardize()) end if opt.zca then table.insert(input_preprocess, dp.ZCA()) end if opt.lecunlcn then table.insert(input_preprocess, dp.GCN()) table.insert(input_preprocess, dp.LeCunLCN{progress=true}) end
不用说,下面当然就到了model的建立啦。model = nn.Sequential()建立初步的框架,下一句的函数Convert大部分用来对数据的处理,就是说把原来的数据转换成特征.例如,mnist的数据集有十个标签,每个数据是28*28的像素,但是问题是,对于多层感知器怎样把他输入图片呢?哈哈,我们把28*28的数据集转换成1*784的数据集。就相当于输入的神经元个数是784个,对吧。这里的bf代表的是batch feature。
model = nn.Sequential() model:add(nn.Convert(ds:ioShapes(), 'bf')) -- to batchSize x nFeature (also type converts)
下面接着是的隐藏层的设定。ds:featureSize就是代表784表示输入神经元的个数。添加的Linera,他的本质是模拟y=ax+b,所以,从hiddenSize中取出两个200,这里的两个200都是描述神隐含神经元的个数,,用于参数的输入。nn.Linear(784,200)),这就建立了两层神经元,输入784个,输出200个神经元的MLP。这里的源代码有点烦,你想加上正规化就加上啊,还写个什么判断语句,搞个整个语句框架看起来不是很舒服。然后加上激活函数层和dropout层。设置下一层的输入为当前层的输出。注意:这里用的是lua的ipairs语法,他会默认的从i=1开始加载,依次加1,如果出现断层,就停止加载。这里的hiddenSize有两个200,也就是说我们添加了两个隐藏层。
inputSize = ds:featureSize() for i,hiddenSize in ipairs(opt.hiddenSize) do model:add(nn.Linear(inputSize, hiddenSize)) -- parameters if opt.batchNorm then model:add(nn.BatchNormalization(hiddenSize)) end model:add(nn[opt.activation]()) if opt.dropout then model:add(nn.Dropout()) end inputSize = hiddenSize end
哈哈,和我们的model的建立模型一致了吧,要是想加上什么dropout,直接设置成为true就可以啦。