首页 > 代码库 > itorch无监督聚类
itorch无监督聚类
cmd = torch.CmdLine()
cmd:text()
cmd:text()用来在terminal上显示运行信息
cmd:option(‘-dir‘, ‘outputs‘, ‘subdirectory to save experiments in‘)
cmd:option用来接受运行时的参数,第一个是参数名称,第二个是默认输入参数,第三个是备注。
1. 处理数据:
dofile ‘1_data.lua‘
dofile和require的功能差不多,不过require不会重新加载,dofile会,于是能够实现动态更新。
require只需要模块名,而dofile由于能动态更新一个模块,所以需要指定路径。
本例之中的数据是以ascii格式的文件。
由于1_data.lua只是简单的对数据进行处理,分块,所以没有写运行函数,所以在dofile之后,还需要调用之中的函数。
filename = paths.basename(params.datafile) if not paths.filep(filename) then os.execute(‘wget ‘ .. params.datafile) end dataset = getdata(filename, params.inputsize) if params.display then displayData(dataset, 100, 10, 2) end
2:建立模型(无监督聚类的精华)
模型的类型可以进行选择,在参数设置时可以调:
已经提供了几种模型进行选择:
auto-encoder class: linear | linear-psd | conv | conv-psd
这之中使用的无监督聚类,就是使用的autoencoding方法。
autoencoding是一个self-training方法。
比较编码前后数据的相似度,降低数据的维度,但是并没有对原有的数据进行分析处理。
(encoder只是网络的名字而已,不要想太多)
encoder = nn.Sequential()
encoder:add(nn.Linear(inputSize,outputSize))
encoder:add(nn.Tanh())
encoder:add(nn.Diag(outputSize))
还有解码层:
decoder = nn.Sequential()
decoder:add(nn.Linear(outputSize,inputSize))
整合两个网络:(一直不知道如何整合两个网络,打开了思路,不过实在不知道为什么autoencoder需要写成两个网络?)
unsup.AutoEncoder(encoder, decoder, params.beta)
然后把autoencoder源代码,如下:
local AutoEncoder = torch.class(‘unsup.AutoEncoder‘,‘unsup.UnsupModule‘) function AutoEncoder:__init(encoder, decoder, beta, loss, lambda, codeloss)--初始化 self.encoder = encoder self.decoder = decoder self.beta = beta if loss then self.loss = loss else self.loss = nn.MSECriterion() self.loss.sizeAverage = false end if lambda and codeloss then self.codecost = codeloss self.lambda = lambda end end function AutoEncoder:parameters() local seq = nn.Sequential() seq:add(self.encoder) seq:add(self.decoder) return seq:parameters() end function AutoEncoder:initDiagHessianParameters() self.encoder:initDiagHessianParameters() self.decoder:initDiagHessianParameters() end function AutoEncoder:reset(stdv) self.decoder:reset(stdv) self.encoder:reset(stdv) end function AutoEncoder:updateOutput(input,target) self.encoder:updateOutput(input) self.decoder:updateOutput(self.encoder.output) self.output = self.beta * self.loss:updateOutput(self.decoder.output, target) if self.lambda then self.output = self.output + self.lambda * self.codecost(self.encoder.output) end return self.output end function AutoEncoder:updateGradInput(input,target) self.loss:updateGradInput(self.decoder.output, target) self.loss.gradInput:mul(self.beta) if self.lambda then self.codecost:updateGradInput(self.encoder.output) self.codecost.gradInput:mul(self.lambda) end self.decoder:updateGradInput(self.encoder.output, self.loss.gradInput) -- accumulate gradients from code cost if self.lambda then self.decoder.gradInput:add(self.codecost.gradInput) end self.encoder:updateGradInput(input, self.decoder.gradInput) self.gradInput = self.encoder.gradInput return self.gradInput end function AutoEncoder:accGradParameters(input,target) self.decoder:accGradParameters(self.encoder.output, self.loss.gradInput) self.encoder:accGradParameters(input, self.decoder.gradInput) end function AutoEncoder:zeroGradParameters() self.encoder:zeroGradParameters() self.decoder:zeroGradParameters() end function AutoEncoder:updateDiagHessianInput(input, diagHessianOutput) self.loss:updateDiagHessianInput(self.decoder.output, target) self.loss.diagHessianInput:mul(self.beta) if self.lambda then self.codecost:updateDiagHessianInput(self.encoder.output) self.codecost.diagHessianInput:mul(self.lambda) end self.decoder:updateDiagHessianInput(self.encoder.output, self.loss.diagHessianInput) -- accumulate gradients from code cost if self.lambda then self.decoder.diagHessianInput:add(self.codecost.diagHessianInput) end self.encoder:updateDiagHessianInput(input, self.decoder.diagHessianInput) self.diagHessianInput = self.encoder.diagHessianInput return self.diagHessianInput end function AutoEncoder:accDiagHessianParameters(input, diagHessianOutput) self.decoder:accDiagHessianParameters(self.encoder.output, self.loss.diagHessianInput) self.encoder:accDiagHessianParameters(input, self.decoder.diagHessianInput) end function AutoEncoder:updateParameters(learningRate) local eta = {} if type(learningRate) ~= ‘number‘ then eta = learningRate else eta[1] = learningRate eta[2] = learningRate end self.encoder:updateParameters(eta[1]) self.decoder:updateParameters(eta[2]) end function AutoEncoder:normalize() if not self.normalized then return end -- normalize the dictionary local w = self.decoder.weight if not w or w:dim() < 2 then return end if w:dim() == 5 then for i=1,w:size(1) do local keri = w:select(1,i) for j=1,w:size(2) do local kerj = keri:select(1,j) for k=1,w:size(3) do local ker = kerj:select(1,k) ker:div(ker:norm()+1e-12) end end end elseif w:dim() == 4 then for i=1,w:size(1) do for j=1,w:size(2) do local k=w:select(1,i):select(1,j) k:div(k:norm()+1e-12) end end elseif w:dim() == 3 then for i=1,w:size(1) do local k=w:select(1,i) k:div(k:norm()+1e-12) end elseif w:dim() == 2 then for i=1,w:size(2) do local k=w:select(2,i) k:div(k:norm()+1e-12) end else error(‘I do not know what kind of weight matrix this is‘) end end
3:训练模型
使用刚才弄出来的model来进行训练。
初始化:(调用unsup中的函数)
initDiagHessianParameters
autoencoder的参数在作者之中变为了hessian矩阵
更新网络:
module:updateGradInput(input, target) module:accGradParameters(input, target)
更新hessian矩阵:
-- hessian ddl_ddx:zero() module:updateDiagHessianInput(input, target) module:accDiagHessianParameters(input, target)
updategradinput函数:
两个网络分别进行迭代
function AutoEncoder:updateGradInput(input,target) self.loss:updateGradInput(self.decoder.output, target) self.loss.gradInput:mul(self.beta) if self.lambda then self.codecost:updateGradInput(self.encoder.output) self.codecost.gradInput:mul(self.lambda) end self.decoder:updateGradInput(self.encoder.output, self.loss.gradInput) -- accumulate gradients from code cost if self.lambda then self.decoder.gradInput:add(self.codecost.gradInput) end self.encoder:updateGradInput(input, self.decoder.gradInput) self.gradInput = self.encoder.gradInput return self.gradInput end
accGradParameters函数:
function AutoEncoder:accGradParameters(input,target) self.decoder:accGradParameters(self.encoder.output, self.loss.gradInput) self.encoder:accGradParameters(input, self.decoder.gradInput) end
updateDiagHessianInput函数:
function AutoEncoder:updateDiagHessianInput(input, diagHessianOutput) self.loss:updateDiagHessianInput(self.decoder.output, target) self.loss.diagHessianInput:mul(self.beta) if self.lambda then self.codecost:updateDiagHessianInput(self.encoder.output) self.codecost.diagHessianInput:mul(self.lambda) end self.decoder:updateDiagHessianInput(self.encoder.output, self.loss.diagHessianInput) -- accumulate gradients from code cost if self.lambda then self.decoder.diagHessianInput:add(self.codecost.diagHessianInput) end self.encoder:updateDiagHessianInput(input, self.decoder.diagHessianInput) self.diagHessianInput = self.encoder.diagHessianInput return self.diagHessianInput end
accDiagHessianParameters函数:
function AutoEncoder:accDiagHessianParameters(input, diagHessianOutput) self.decoder:accDiagHessianParameters(self.encoder.output, self.loss.diagHessianInput) self.encoder:accDiagHessianParameters(input, self.decoder.diagHessianInput) end
train中整合decoder和encoder的hessian矩阵:
ddl_ddx_avg:add(1/hessiansamples, ddl_ddx)
由于神经网络训练优化迭代速度的方法就是把训练块减小:(分块多步)
local example = dataset[t] local inputs = {} local targets = {} for i = t,t+params.batchsize-1 do -- load new sample local sample = dataset[i] local input = sample[1]:clone() local target = sample[2]:clone() table.insert(inputs, input) table.insert(targets, target) end
计算每块的f和dx,loss函数自己定义
local feval = function() -- reset gradient/f local f = 0 dl_dx:zero() -- estimate f and gradients, for minibatch for i = 1,#inputs do -- f f = f + module:updateOutput(inputs[i], targets[i]) -- gradients module:updateGradInput(inputs[i], targets[i]) module:accGradParameters(inputs[i], targets[i]) end -- normalize dl_dx:div(#inputs) f = f/#inputs -- return f and df/dx return f,dl_dx end
使用sgd来计算梯度:
sgdconf = sgdconf or {learningRate = params.eta, learningRateDecay = params.etadecay, learningRates = etas, momentum = params.momentum} _,fs = optim.sgd(feval, x, sgdconf) err = err + fs[1]*params.batchsize -- so that err is indep of batch size
均值化参数:
-- normalize if params.model:find(‘psd‘) then module:normalize() end
normalize函数:
function AutoEncoder:normalize() if not self.normalized then return end -- normalize the dictionary local w = self.decoder.weight if not w or w:dim() < 2 then return end if w:dim() == 5 then for i=1,w:size(1) do local keri = w:select(1,i) for j=1,w:size(2) do local kerj = keri:select(1,j) for k=1,w:size(3) do local ker = kerj:select(1,k) ker:div(ker:norm()+1e-12) end end end elseif w:dim() == 4 then for i=1,w:size(1) do for j=1,w:size(2) do local k=w:select(1,i):select(1,j) k:div(k:norm()+1e-12) end end elseif w:dim() == 3 then for i=1,w:size(1) do local k=w:select(1,i) k:div(k:norm()+1e-12) end elseif w:dim() == 2 then for i=1,w:size(2) do local k=w:select(2,i) k:div(k:norm()+1e-12) end else error(‘I do not know what kind of weight matrix this is‘) end end
然后就是显示err
if iter*params.batchsize >= params.statinterval then
最后保存数据:
dd = image.toDisplayTensor{input=dweight, padding=2, nrow=math.floor(math.sqrt(params.nfiltersout)), symmetric=true} de = image.toDisplayTensor{input=eweight, padding=2, nrow=math.floor(math.sqrt(params.nfiltersout)), symmetric=true}
贴上autoencoder的代码:
local AutoEncoder = torch.class(‘unsup.AutoEncoder‘,‘unsup.UnsupModule‘) function AutoEncoder:__init(encoder, decoder, beta, loss, lambda, codeloss) self.encoder = encoder self.decoder = decoder self.beta = beta if loss then self.loss = loss else self.loss = nn.MSECriterion() self.loss.sizeAverage = false end if lambda and codeloss then self.codecost = codeloss self.lambda = lambda end end function AutoEncoder:parameters() local seq = nn.Sequential() seq:add(self.encoder) seq:add(self.decoder) return seq:parameters() end function AutoEncoder:initDiagHessianParameters() self.encoder:initDiagHessianParameters() self.decoder:initDiagHessianParameters() end function AutoEncoder:reset(stdv) self.decoder:reset(stdv) self.encoder:reset(stdv) end function AutoEncoder:updateOutput(input,target) self.encoder:updateOutput(input) self.decoder:updateOutput(self.encoder.output) self.output = self.beta * self.loss:updateOutput(self.decoder.output, target) if self.lambda then self.output = self.output + self.lambda * self.codecost(self.encoder.output) end return self.output end function AutoEncoder:updateGradInput(input,target) self.loss:updateGradInput(self.decoder.output, target) self.loss.gradInput:mul(self.beta) if self.lambda then self.codecost:updateGradInput(self.encoder.output) self.codecost.gradInput:mul(self.lambda) end self.decoder:updateGradInput(self.encoder.output, self.loss.gradInput) -- accumulate gradients from code cost if self.lambda then self.decoder.gradInput:add(self.codecost.gradInput) end self.encoder:updateGradInput(input, self.decoder.gradInput) self.gradInput = self.encoder.gradInput return self.gradInput end function AutoEncoder:accGradParameters(input,target) self.decoder:accGradParameters(self.encoder.output, self.loss.gradInput) self.encoder:accGradParameters(input, self.decoder.gradInput) end function AutoEncoder:zeroGradParameters() self.encoder:zeroGradParameters() self.decoder:zeroGradParameters() end function AutoEncoder:updateDiagHessianInput(input, diagHessianOutput) self.loss:updateDiagHessianInput(self.decoder.output, target) self.loss.diagHessianInput:mul(self.beta) if self.lambda then self.codecost:updateDiagHessianInput(self.encoder.output) self.codecost.diagHessianInput:mul(self.lambda) end self.decoder:updateDiagHessianInput(self.encoder.output, self.loss.diagHessianInput) -- accumulate gradients from code cost if self.lambda then self.decoder.diagHessianInput:add(self.codecost.diagHessianInput) end self.encoder:updateDiagHessianInput(input, self.decoder.diagHessianInput) self.diagHessianInput = self.encoder.diagHessianInput return self.diagHessianInput end function AutoEncoder:accDiagHessianParameters(input, diagHessianOutput) self.decoder:accDiagHessianParameters(self.encoder.output, self.loss.diagHessianInput) self.encoder:accDiagHessianParameters(input, self.decoder.diagHessianInput) end function AutoEncoder:updateParameters(learningRate) local eta = {} if type(learningRate) ~= ‘number‘ then eta = learningRate else eta[1] = learningRate eta[2] = learningRate end self.encoder:updateParameters(eta[1]) self.decoder:updateParameters(eta[2]) end function AutoEncoder:normalize() if not self.normalized then return end -- normalize the dictionary local w = self.decoder.weight if not w or w:dim() < 2 then return end if w:dim() == 5 then for i=1,w:size(1) do local keri = w:select(1,i) for j=1,w:size(2) do local kerj = keri:select(1,j) for k=1,w:size(3) do local ker = kerj:select(1,k) ker:div(ker:norm()+1e-12) end end end elseif w:dim() == 4 then for i=1,w:size(1) do for j=1,w:size(2) do local k=w:select(1,i):select(1,j) k:div(k:norm()+1e-12) end end elseif w:dim() == 3 then for i=1,w:size(1) do local k=w:select(1,i) k:div(k:norm()+1e-12) end elseif w:dim() == 2 then for i=1,w:size(2) do local k=w:select(2,i) k:div(k:norm()+1e-12) end else error(‘I do not know what kind of weight matrix this is‘) end end
itorch无监督聚类