2 -- Francois Fleuret's Torch Toolbox
7 ----------------------------------------------------------------------
11 function printf(f, ...)
12 print(string.format(f, unpack({...})))
15 function printfc(c, f, ...)
16 printf(c .. string.format(f, unpack({...})) .. colors.black)
19 function logCommand(c)
20 print(colors.blue .. '[' .. c .. '] -> [' .. sys.execute(c) .. ']' .. colors.black)
23 ----------------------------------------------------------------------
24 -- Environment variables
29 if os.getenv('TORCH_NB_THREADS') then
30 defaultNbThreads = os.getenv('TORCH_NB_THREADS')
31 print('Environment variable TORCH_NB_THREADS is set and equal to ' .. defaultNbThreads)
33 print('Environment variable TORCH_NB_THREADS is not set, default is ' .. defaultNbThreads)
36 if os.getenv('TORCH_USE_GPU') then
37 defaultUseGPU = os.getenv('TORCH_USE_GPU') == 'yes'
38 print('Environment variable TORCH_USE_GPU is set and evaluated as ' .. tostring(defaultUseGPU))
40 print('Environment variable TORCH_USE_GPU is not set, default is ' .. tostring(defaultUseGPU))
43 ----------------------------------------------------------------------
45 function fftbInit(cmd, params)
47 torch.setnumthreads(params.nbThreads)
48 torch.setdefaulttensortype('torch.FloatTensor')
49 torch.manualSeed(params.seed)
53 if params.rundir == '' then
54 params.rundir = cmd:string('experiment', params, { })
57 paths.mkdir(params.rundir)
59 if not params.noLog then
60 -- Append to the log if there is one
61 cmd:log(io.open(params.rundir .. '/log', 'a'), params)
64 -- Dealing with the CPU/GPU
68 -- By default, ffnn returns the entries from nn
70 function mt.__index(table, key)
71 return (cudnn and cudnn[key]) or (cunn and cunn[key]) or nn[key]
73 setmetatable(ffnn, mt)
75 -- These are the tensors that can be kept on the CPU
76 ffnn.SlowTensor = torch.Tensor
77 ffnn.SlowStorage = torch.Storage
78 -- These are the tensors that should be moved to the GPU
79 ffnn.FastTensor = torch.Tensor
80 ffnn.FastStorage = torch.Storage
87 if params.fastGPU then
88 cudnn.benchmark = true
92 ffnn.FastTensor = torch.CudaTensor
93 ffnn.FastStorage = torch.CudaStorage
97 ----------------------------------------------------------------------
99 function dimAtThatPoint(model, input)
100 if params.useGPU then
103 local i = ffnn.FastTensor(input:narrow(1, 1, 1):size()):copy(input:narrow(1, 1, 1))
104 return model:forward(i):nElement()
107 ----------------------------------------------------------------------
109 function sizeForBatch(n, x)
110 local size = x:size()
115 function fillBatch(data, first, batch, permutation)
116 local actualBatchSize = math.min(params.batchSize, data.input:size(1) - first + 1)
119 if actualBatchSize ~= batch.input:size(1) then
120 batch.input:resize(sizeForBatch(actualBatchSize, batch.input))
123 if torch.isTypeOf(data.input, ffnn.SlowTensor) then
124 batch.input = ffnn.FastTensor(sizeForBatch(actualBatchSize, data.input));
126 batch.input = data.input.new():resize(sizeForBatch(actualBatchSize, data.input));
131 if actualBatchSize ~= batch.target:size(1) then
132 batch.target:resize(sizeForBatch(actualBatchSize, batch.target))
135 if torch.isTypeOf(data.target, ffnn.SlowTensor) then
136 batch.target = ffnn.FastTensor(sizeForBatch(actualBatchSize, data.target));
138 batch.target = data.target.new():resize(sizeForBatch(actualBatchSize, data.target));
142 for k = 1, actualBatchSize do
145 i = permutation[first + k - 1]
149 batch.input[k] = data.input[i]
150 batch.target[k] = data.target[i]
154 ----------------------------------------------------------------------
158 The combineImage function takes as input a parameter c which is the
159 value to use for the background of the resulting image (padding and
160 such), and t which is either a 2d tensor, a 3d tensor, or a table.
162 * If t is a 3d tensor, it is returned unchanged.
164 * If t is a 2d tensor [r x c], it is reshaped to [1 x r x c] and
167 * If t is a table, combineImage first calls itself recursively on
170 It then creates a new tensor by concatenating the results
171 horizontally if t.vertical is nil, vertically otherwise.
173 It adds a padding of t.pad pixels if this field is set.
177 x = torch.Tensor(64, 64):fill(0.5)
178 y = torch.Tensor(100, 30):fill(0.85)
180 i = combineImages(1.0,
187 { pad = 4, torch.Tensor(32, 16):fill(0.25) },
188 { pad = 1, torch.Tensor(45, 54):uniform(0.25, 0.9) },
193 image.save('example.png', i)
197 function combineImages(c, t)
199 if torch.isTensor(t) then
203 elseif t:dim() == 2 then
204 return torch.Tensor(1, t:size(1), t:size(2)):copy(t)
206 error('can only deal with [height x width] or [channel x height x width] tensors.')
211 local subImages = {} -- The subimages
212 local nc = 0 -- Nb of columns
213 local nr = 0 -- Nb of rows
215 for i, x in ipairs(t) do
216 subImages[i] = combineImages(c, x)
218 nr = nr + subImages[i]:size(2)
219 nc = math.max(nc, subImages[i]:size(3))
221 nr = math.max(nr, subImages[i]:size(2))
222 nc = nc + subImages[i]:size(3)
226 local pad = t.pad or 0
227 local result = torch.Tensor(subImages[1]:size(1), nr + 2 * pad, nc + 2 * pad):fill(c)
228 local co = 1 + pad -- Origin column
229 local ro = 1 + pad -- Origin row
231 for i in ipairs(t) do
234 :sub(1, subImages[1]:size(1),
235 ro, ro + subImages[i]:size(2) - 1,
236 co, co + subImages[i]:size(3) - 1)
240 ro = ro + subImages[i]:size(2)
242 co = co + subImages[i]:size(3)
255 The imageFromTensors function gets as input a list of tensors of
256 arbitrary dimensions each, but whose two last dimensions stand for
257 height x width. It creates an image tensor (2d, one channel) with each
258 argument tensor unfolded per row.
262 function imageFromTensors(bt, signed)
268 for _, t in pairs(bt) do
270 local h, w = t:size(d - 1), t:size(d)
271 local n = t:nElement() / (w * h)
272 width = math.max(width, gap + n * (gap + w))
273 height = height + gap + tgap + gap + h
276 local e = torch.Tensor(3, height, width):fill(1.0)
279 for _, t in pairs(bt) do
281 local h, w = t:size(d - 1), t:size(d)
282 local n = t:nElement() / (w * h)
283 local z = t:norm() / math.sqrt(t:nElement())
285 local x0 = 1 + gap + math.floor( (width - n * (w + gap)) /2 )
286 local u = torch.Tensor(t:size()):copy(t):resize(n, h, w)
291 e[c][y0 + y - 1][x0 - 1] = 0.0
292 e[c][y0 + y - 1][x0 + w ] = 0.0
295 e[c][y0 - 1][x0 + x - 1] = 0.0
296 e[c][y0 + h ][x0 + x - 1] = 0.0
302 local v = u[m][y][x] / z
306 r, g, b = 0.0, 0.0, 1.0
308 r, g, b = 1.0, 0.0, 0.0
310 r, g, b = 1.0, 1.0 - v, 1.0 - v
312 r, g, b = 1.0 + v, 1.0 + v, 1.0
316 r, g, b = 1.0, 1.0, 1.0
318 r, g, b = 0.0, 0.0, 0.0
320 r, g, b = 1.0 - v, 1.0 - v, 1.0 - v
323 e[1][y0 + y - 1][x0 + x - 1] = r
324 e[2][y0 + y - 1][x0 + x - 1] = g
325 e[3][y0 + y - 1][x0 + x - 1] = b
330 y0 = y0 + h + gap + tgap + gap