In [1]:
require 'nn'
require 'optim'

In [2]:
local matio = require 'matio'
data = matio.load('ex3data1.mat')

In [3]:
dataset_inputs = data.X

In [4]:
mean = {}
stdv = {}
for i=1,400 do
    mean[i] = dataset_inputs[{ {},{i} }]:mean()
    stdv[i] = dataset_inputs[{ {}, {i} }]:std()
    dataset_inputs[{ {},{i} }]:add(-mean[i])
    dataset_inputs[{ {},{i} }]:div(stdv[i])
end

In [5]:
dataset_outputs = data.y

In [6]:
numOutput = torch.max(dataset_outputs) - torch.min(dataset_outputs) + 1

In [7]:
linLayer = nn.Linear(400,10)

In [8]:
model = nn.Sequential()
model:add(linLayer)
model:add(nn.Sigmoid())
model:add(nn.LogSoftMax())

In [9]:
model


Out[9]:
nn.Sequential {
  [input -> (1) -> (2) -> output]
  (1): nn.Linear(400 -> 10)
  (2): nn.Sigmoid
}
{
  gradInput : DoubleTensor - empty
  modules : 
    {
      1 : 
        nn.Linear(400 -> 10)
        {
          gradBias : DoubleTensor - size: 10
          weight : DoubleTensor - size: 10x400
          bias : DoubleTensor - size: 10
          gradInput : DoubleTensor - empty
          gradWeight : DoubleTensor - size: 10x400
          output : DoubleTensor - empty
        }
      2 : 
        nn.Sigmoid
        {
          gradInput : DoubleTensor - empty
          output : DoubleTensor - empty
    

In [10]:
criterion = nn.ClassNLLCriterion()


Out[10]:
    }
    }
  output : DoubleTensor - empty
}

In [11]:
x, dl_dx = model:getParameters()

In [12]:
feval = function()
    _nidx_ = (_nidx_ or 0) + 1
    if _nidx_ > (#dataset_inputs)[1] then _nidx_ = 1 end
    
    local inputs = dataset_inputs[_nidx_]
    local target = dataset_outputs[_nidx_]
    
    dl_dx:zero()
    
    local loss_x = criterion:forward(model:forward(inputs), target)
    model:backward(inputs, criterion:backward(model.output, target))
        
    return loss_x, dl_dx
end

In [13]:
sgd_params = {
    learningRate = 1e-3,
    learningRateDecay = 1e-4,
    weightDecay = 0,
    momentum = 0
}

In [14]:
epochs = 1e1

In [15]:
for i = 1, epochs do
    current_loss = 0
    for i = 1, (#dataset_inputs)[1] do
        _, fs = optim.sgd(feval, x, sgd_params)
        current_loss = current_loss + fs[1]
    end
    
    current_loss = current_loss / (#dataset_inputs)[1]
    if i%10 == 1 then
        print('epoch = ' .. i .. ' of ' .. epochs .. ' current loss = ' .. current_loss)
    end
end


Out[15]:
epoch = 1 of 10 current loss = nan	

In [16]:
function maxIndex(a)
    local idx = 0
    local mx = -1e5
    for i = 1,(#a)[1] do
        if mx < a[i] then
            mx = a[i]
            idx = i
        end
    end
    return idx
end

In [17]:
acc = 0.0
for i = 1, (#dataset_inputs)[1] do
    if (maxIndex(model:forward(dataset_inputs[i])) == dataset_outputs[i][1]) then
        acc = acc + 1
    end
end
print('accuracy: ' .. acc/(#dataset_inputs)[1])


Out[17]:
accuracy: 0