首页 > 代码库 > 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无监督聚类