-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.lua
284 lines (239 loc) · 9.45 KB
/
main.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
require 'torch'
require 'nn'
require 'cutorch'
require 'cudnn'
require 'image'
require 'optim'
require 'pl'
--
-- Global vars
--
opt = lapp[[
-p,--prepair_samples prepair samples using pre-trained cnn
-n,--num_samples (default 5) number of samples to prepair (only useful with -p)
-d,--display_images display image samples during preparation (only useful with -p)
-r,--learning_rate (default 0.05) learning rate
-m,--momentum (default 0.5) momentum
-e,--num_epochs (default 500) number of epochs
-s,--sanity sanity test (train and test with training set)
-t,--threads (default 4) number of threads
]]
--
-- Global settings
--
local net_utils = {}
-- fix seed
torch.manualSeed(1)
-- threads
torch.setnumthreads(opt.threads)
print('Set number of threads to ' .. torch.getnumthreads())
-- use floats (good for SGD)
torch.setdefaulttensortype('torch.FloatTensor')
------------------------------------------------------------------------------
-- takes a batch of images and preprocesses them
-- VGG-16 network is hardcoded, as is 224 as size to forward
local function prepro(imgs, data_augment, on_gpu)
assert(data_augment ~= nil, 'pass this in. careful here.')
assert(on_gpu ~= nil, 'pass this in. careful here.')
local h,w = imgs:size(3), imgs:size(4)
local cnn_input_size = 224
-- cropping data augmentation, if needed
if h > cnn_input_size or w > cnn_input_size then
local xoff, yoff
if data_augment then
xoff, yoff = torch.random(w-cnn_input_size), torch.random(h-cnn_input_size)
else
-- sample the center
xoff, yoff = math.ceil((w-cnn_input_size)/2), math.ceil((h-cnn_input_size)/2)
end
-- crop.
imgs = imgs[{ {}, {}, {yoff,yoff+cnn_input_size-1}, {xoff,xoff+cnn_input_size-1} }]
end
-- ship to gpu or convert from byte to float
if on_gpu then
print("Conversion to float on gpu")
imgs = imgs:cuda()
else
print("Conversion to float on cpu")
imgs = imgs:float()
end
-- lazily instantiate vgg_mean
if not net_utils.vgg_mean then
net_utils.vgg_mean = torch.FloatTensor{123.68, 116.779, 103.939}:view(1,3,1,1) -- in RGB order
end
net_utils.vgg_mean = net_utils.vgg_mean:typeAs(imgs) -- a noop if the types match
-- subtract vgg mean
imgs:add(-1, net_utils.vgg_mean:expandAs(imgs))
return imgs
end
local function load_images_and_labels(csv_name, year, dataset_prefix)
local csv = require("csv")
local f = csv.open(csv_name)
local i = -1
local x, y, px, py, img_file_name
local num_imgs = opt.num_samples
local imgs = torch.Tensor(num_imgs, 3, 224, 224)
local labels = torch.Tensor(num_imgs)
for fields in f:lines() do
if i ~= -1 then
local label
for j, v in ipairs(fields) do
if j == 1 then img_file_name = year .. v .. ".bb08.l.png" end
if j == 2 then x = tonumber(v) end
if j == 3 then y = tonumber(v) end
if j == 4 then label = tonumber(v) end
end
if i >= 1 and i <= num_imgs then
print(img_file_name, ' dist = ', math.sqrt((x - px) * (x - px) + (y - py) * (y - py)))
local img = image.load(img_file_name, 3, 'byte')
img = image.scale(img, 224, 224, 'bilinear')
imgs[i] = img
labels[i] = label
if opt.display_images then
image.display{image = imgs[i], zoom = 1, legend = 'image ' .. tostring(i)}
end
end
px = x
py = y
end
i = i + 1
end
imgs = prepro(imgs, false, true) -- preprocess in place, and don't augment
return imgs, labels
end -- load_images_and_labels()
local function compute_cnn_output_for_images(images)
local batch_size = 10
local images_batch = images:split(batch_size, 1)
local cnn_output
local j = 1
for i = 1, images:size(1), batch_size do
xlua.progress(i, images:size(1)) -- Data preparation progress bar
local images_batch_i = images_batch[j]:clone()
images_batch_i = images_batch_i:cuda()
local cnn_output_i
if j == 1 then
cnn_output_i = cnn_model:forward(images_batch_i)
cnn_output = cnn_output_i:clone()
else
cnn_output_i = cnn_model:forward(images_batch_i)
local cnn_output_ic = cnn_output_i:clone()
cnn_output = torch.cat(cnn_output, cnn_output_ic, 1)
end
j = j + 1
end
return cnn_output
end -- compute_cnn_output_for_images()
local function prepair_samples_using_cnn(csv_name, year, dataset_prefix)
print("Generating samples for " .. dataset_prefix .. " " .. csv_name)
local images, labels = load_images_and_labels(csv_name, year, dataset_prefix)
local cnn_output = compute_cnn_output_for_images(images)
torch.save(dataset_prefix .. "_images.tensor", images)
torch.save(dataset_prefix .. "_labels.tensor", labels)
torch.save(dataset_prefix .. "_cnn_out.tensor", cnn_output)
if opt.display_images then
for i = 1, images:size(1), 1 do
local cnn_output_ret = torch.reshape(cnn_output[i], 24, 32)
--local cnn_output_image = image.scale(cnn_output_ret:double(), 32*8, 24*8, 'simple')
image.display{image = images[i], zoom = 1, legend = 'image ' .. tostring(i)}
image.display{image = cnn_output_ret, zoom = 8, legend = 'model ' .. tostring(i)}
end
end
end -- prepair_samples()
local function build_net(cnn_output, labels)
-- define model to train
model = nn.Sequential()
model:add(nn.Linear(cnn_output:size(2), 200))
model:add(nn.ReLU())
model:add(nn.Linear(200, labels:max()))
model:add(nn.LogSoftMax())
-- a negative log-likelihood criterion for multi-class classification
criterion = nn.ClassNLLCriterion()
end -- build_net()
local function train_net(batchInputs, batchLabels)
-- https://github.com/torch/nn/blob/master/doc/training.md
local optimState = {learningRate = opt.learning_rate, momentum = opt.momentum, learningRateDecay = 5e-7}
--model = model:cuda()
--batchInputs = batchInputs:cuda();
--batchLabels = batchLabels:cuda();
--criterion = criterion:cuda();
local params, gradParams = model:getParameters()
for epoch=1,opt.num_epochs do
xlua.progress(epoch, opt.num_epochs) -- Show traning progress bar
-- local function we give to optim
-- it takes current weights as input, and outputs the loss
-- and the gradient of the loss with respect to the weights
-- gradParams is calculated implicitly by calling 'backward',
-- because the model's weight and bias gradient tensors
-- are simply views onto gradParams
local function feval(params)
gradParams:zero()
local outputs = model:forward(batchInputs)
--outputs = outputs:cuda();
local loss = criterion:forward(outputs, batchLabels)
local dloss_doutput = criterion:backward(outputs, batchLabels)
--dloss_doutput = dloss_doutput:cuda()
model:backward(batchInputs, dloss_doutput)
return loss,gradParams
end
--feval(params)
optim.sgd(feval, params, optimState)
--print("epoch = ", epoch)
end
end -- train_net()
local function evaluate_resuts(results, labels)
-- this matrix records the current confusion across classes
local confusion = optim.ConfusionMatrix(labels:max())
for i = 1,results:size(1) do
confusion:add(results[i], labels[i])
end
print(confusion)
-- print(results:exp())
-- print(results:size())
-- for i = 1, results:size(1) do
-- local max, indice = torch.max(results[i], 1)
-- print("max, indice, label", max:max(), indice:max(), labels[i])
-- end
end -- evaluate_resuts()
local function test_net(cnn_output, labels)
local results = model:forward(cnn_output)
evaluate_resuts(results, labels)
end -- test_net()
local function main()
if opt.prepair_samples then
print("Preparing Samples...\n")
cnn_model = torch.load('/home/alberto/neuraltalk2/cnn.model')
cnn_model = cnn_model:cuda()
-- print(cnn_model)
cnn_model:evaluate()
-- local images = torch.load('/home/alberto/neuraltalk2/image.data')
print("- Training Samples\n")
prepair_samples_using_cnn("/dados/GPS_clean/UFES-2012-30-train.csv", "/dados/GPS_clean/2012/", "training") -- depois que preparar, nao precisa rodar de novo
print("- Test Samples\n")
prepair_samples_using_cnn("/dados/GPS_clean/UFES-2014-30-train.csv", "/dados/GPS_clean/2014/", "test") -- depois que preparar, nao precisa rodar de novo
end
local images = torch.load("training_images.tensor")
local cnn_output = torch.load("training_cnn_out.tensor")
local labels = torch.load("training_labels.tensor")
print("++++ Build net")
build_net(cnn_output, labels)
-- print(model)
-- treinar a rede com cada cnn_output (input) com o label correspondente (target)
print("++++ Train net")
train_net(cnn_output:float(), labels)
print()
-- testar com as images de 2012 (teste de sanidade) e depois com images de 2014 (tem que ler e gerar tensor em forma de arquivo)
local test_images, test_cnn_output, test_labels
if opt.sanity then
print("==== Test net: sanity test! ====")
test_images = torch.load("training_images.tensor")
test_cnn_output = torch.load("training_cnn_out.tensor")
test_labels = torch.load("training_labels.tensor")
else
print("==== Test net: real test! ====")
test_images = torch.load("test_images.tensor")
test_cnn_output = torch.load("test_cnn_out.tensor")
test_labels = torch.load("test_labels.tensor")
end
test_net(test_cnn_output:float(), test_labels) -- os mesmos <images, labels> (sanidade) ou os de 2014
end -- main()
main()