FloorPlanTransformation / util /lua /nn_utils.lua
rawanessam's picture
Upload 79 files
e9fe176 verified
Raw History Blame Contribute Delete
22.2 kB
require 'torch'
require 'image'
require 'paths'
require 'nn'
require 'inn'
require 'image'
require 'xlua'
require 'cudnn'
require 'loadcaffe'
local gp = require 'gpath'
local nn_utils = {}
nn_utils.mean = torch.Tensor({129.67, 114.43, 107.26})
nn_utils.nmean = nn_utils.mean:clone():div(255)
-------------------------------------------------------------------
-- generate an image of a particular size with values scaled in [0, 1] and
-- then mean substracted
function nn_utils.normalize(im, width, height, nmean)
nmean = nmean or nn_utils.nmean
assert((#im)[1] == (#nmean)[1])
-- scale the image
local normalized = image.scale(im, width, height)
-- normalize it to [0, 1]
if normalized:max() > 1 then
normalized:div(255)
end
-- mean subtraction
for i = 1, (#nmean)[1] do
normalized[i]:csub(nmean[i])
end
return normalized
end
-- add mean value back
function nn_utils.unnormalize(im, nmean)
nmean = nmean or nn_utils.nmean
assert((#im)[1] == (#nmean)[1])
local unnorm = im:clone()
for i = 1, (#nmean)[1] do
unnorm[i]:add(nmean[i])
end
return unnorm
end
function nn_utils.loadNormalizeIm(imName, numChn, width, height)
numChn = numChn or 3
local im = image.load(imName)
if im:size(1) == 1 and numChn == 3 then
im = torch.repeatTensor(im, 3, 1, 1)
end
-- normalize image
im = nn_utils.normalize(im, width, height, mean)
return im
end
function nn_utils.toCaffeInput(input, fullScale, swapChn, width, height, mean)
assert(input:dim() == 4 and input:size(2) == 3 or
input:dim() == 3 and input:size(1) == 3)
fullScale = fullScale or true
swapChn = swapChn or true
width = width or 227
height = height or 227
mean = mean or nn_utils.mean
if input:dim() == 4 then
local bs = input:size(1)
local ch = input:size(2)
local ht = input:size(3)
local wd = input:size(4)
input = image.scale(input:view(bs * ch, ht, wd),
width, height):view(bs, ch, height, width)
else
local ch = input:size(1)
local ht = input:size(2)
local wd = input:size(3)
input = image.scale(input, width, height)
end
local maxV = input:max()
local minV = input:min()
if fullScale then
if math.abs(maxV) <= 1 and math.abs(minV) <= 1 then
input:mul(255)
end
if maxV >= 0.5 and minV >= 0 then
if input:dim() == 4 then
for i = 1, 3 do
input[{{}, i, {}, {}}]:csub(mean[i])
end
else
for i = 1, 3 do
input[{i, {}, {}}]:csub(mean[i])
end
end
end
else
if math.abs(maxV) > 1 or math.abs(minV) > 1 then
input:div(255)
end
if maxV >= 0.5 and minV >= 0 then
if input:dim() == 4 then
for i = 1, 3 do
input[{{}, i, {}, {}}]:csub(mean[i]/255)
end
else
for i = 1, 3 do
input[{i, {}, {}}]:csub(mean[i]/255)
end
end
end
end
if swapChn then
if input:dim() == 4 then
local tmp = input[{{}, 1, {}, {}}]:clone()
input[{{}, 1, {}, {}}] = input[{{}, 3, {}, {}}]
input[{{}, 3, {}, {}}] = tmp
else
local tmp = input[{1, {}, {}}]:clone()
input[{1, {}, {}}] = input[{3, {}, {}}]
input[{3, {}, {}}] = tmp
end
end
return input
end
-----------------------------------------------------------------------------
--
function nn_utils.loadLeNet(net)
net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'lenet')
return loadcaffe.load(paths.concat(modelPath, 'lenet.prototxt'),
paths.concat(modelPath, 'lenet_iter_10000.caffemodel'), net)
end
function nn_utils.loadAlexNet(net)
net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'bvlc_alexnet')
return loadcaffe.load(paths.concat(modelPath, 'deploy.prototxt'),
paths.concat(modelPath, 'bvlc_alexnet.caffemodel'), net)
end
-- not working
function nn_utils.loadPlacesAlexNet(net)
print('Warning: loadFasterRCNNZF is not working')
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'places205_alexnet')
return loadcaffe.load(paths.concat(modelPath, 'places205CNN_deploy_torch.prototxt'),
paths.concat(modelPath, 'places205CNN_iter_300000.caffemodel'), net)
end
-- not working
function nn_utils.loadHybridAlexNet(net)
print('Warning: loadFasterRCNNZF is not working')
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'hybrid_alexnet')
return loadcaffe.load(paths.concat(modelPath, 'hybridCNN_deploy.prototxt'),
paths.concat(modelPath, 'hybridCNN_iter_700000.caffemodel'), net)
end
function nn_utils.loadCaffeNet(net)
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'bvlc_reference_caffenet')
return loadcaffe.load(paths.concat(modelPath, 'deploy.prototxt'),
paths.concat(modelPath, 'bvlc_reference_caffenet.caffemodel'), net)
end
function nn_utils.loadVGG16(net)
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'vgg_16')
return loadcaffe.load(paths.concat(modelPath, 'VGG_ILSVRC_16_layers_deploy.prototxt'),
paths.concat(modelPath, 'VGG_ILSVRC_16_layers.caffemodel'), net)
end
function nn_utils.loadVGG19(net)
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'vgg_19')
return loadcaffe.load(paths.concat(modelPath, 'VGG_ILSVRC_19_layers_deploy.prototxt'),
paths.concat(modelPath, 'VGG_ILSVRC_19_layers.caffemodel'), net)
end
function nn_utils.loadGoogleNet(net)
local modelPath = paths.concat(gp.caffe_model, 'googlenet')
return torch.load(paths.concat(modelPath, 'inceptionv3.net'))
end
function nn_utils.loadResNet18()
local modelPath = paths.concat(gp.caffe_model, 'resnet_18')
return torch.load(paths.concat(modelPath, 'resnet-18.t7'))
end
function nn_utils.loadResNet34()
local modelPath = paths.concat(gp.caffe_model, 'resnet_34')
return torch.load(paths.concat(modelPath, 'resnet-34.t7'))
end
function nn_utils.loadResNet50()
local modelPath = paths.concat(gp.caffe_model, 'resnet_50')
return torch.load(paths.concat(modelPath, 'resnet-50.t7'))
end
function nn_utils.loadResNet101()
local modelPath = paths.concat(gp.caffe_model, 'resnet_101')
return torch.load(paths.concat(modelPath, 'resnet-101.t7'))
end
function nn_utils.loadResNet152()
local modelPath = paths.concat(gp.caffe_model, 'resnet_152')
return torch.load(paths.concat(modelPath, 'resnet-152.t7'))
end
function nn_utils.loadResNet200()
local modelPath = paths.concat(gp.caffe_model, 'resnet_200')
return torch.load(paths.concat(modelPath, 'resnet-200.t7'))
end
function nn_utils.loadRCNN(net)
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'bvlc_reference_rcnn_ilsvrc13')
return loadcaffe.load(paths.concat(modelPath, 'deploy.prototxt'),
paths.concat(modelPath, 'bvlc_reference_rcnn_ilsvrc13.caffemodel'), net)
end
function nn_utils.loadFastRCNNCaffeNet()
local modelPath = paths.concat(gp.caffe_model, 'fastrcnn')
return torch.load(paths.concat(modelPath, 'caffenet_fast_rcnn_iter_40000.t7')):unpack()
end
function nn_utils.loadFastRCNNVGG16()
local modelPath = paths.concat(gp.caffe_model, 'fastrcnn')
return torch.load(paths.concat(modelPath, 'vgg16_fast_rcnn_iter_40000.t7')):unpack()
end
function nn_utils.loadFCN32s(net)
local modelPath = paths.concat(gp.caffe_model, 'fcn_32s_pascal')
return torch.load(paths.concat(modelPath, 'fcn_32s_pascal.t7'))
end
function nn_utils.loadFCN32sRaw(net)
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'fcn_32s_pascal')
return loadcaffe.load(paths.concat(modelPath, 'fcn-32s-pascal-deploy.prototxt'),
paths.concat(modelPath, 'fcn-32s-pascal.caffemodel'), net)
end
function nn_utils.loadNIN(net)
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'nin')
return loadcaffe.load(paths.concat(modelPath, 'train_val.prototxt'),
paths.concat(modelPath, 'nin_imagenet_conv.caffemodel'), net)
end
-- not working
function nn_utils.loadFasterRCNNZF(net)
print('Warning: loadFasterRCNNZF is not working')
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'faster_rcnn_VOC0712_ZF')
return loadcaffe.load(paths.concat(modelPath, 'deploy.prototxt'),
paths.concat(modelPath, 'ZF_faster_rcnn_final.caffemodel'), net)
end
-- not working
function nn_utils.loadFasterRCNNVGG(net)
print('Warning: loadFasterRCNNVGG is not working')
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'faster_rcnn_VOC0712_vgg_16layers')
return loadcaffe.load(paths.concat(modelPath, 'deploy.prototxt'),
paths.concat(modelPath, 'VGG16_faster_rcnn_final.caffemodel'), net)
end
-- not working
function nn_utils.loadHED(net)
print('Warning: loadHED is not working')
local net = net or 'cudnn'
local modelPath = paths.concat(gp.caffe_model, 'hed')
return loadcaffe.load(paths.concat(modelPath, 'hed.prototxt'),
paths.concat(modelPath, 'hed_bsds.caffemodel'), net)
end
------------------------------------------------------------------------
function nn_utils.sanitize(net)
local list = net:listModules()
for nameL, val in ipairs(list) do
for name, field in pairs(val) do
if torch.type(field) == 'cdata' then val[name] = nil end
if name == 'homeGradBuffers' then val[name] = nil end
if name == 'input_gpu' then val['input_gpu'] = {} end
if name == 'gradOutput_gpu' then val['gradOutput_gpu'] = {} end
if name == 'gradInput_gpu' then val['gradInput_gpu'] = {} end
--if (name == 'output' or name == 'gradInput' or
-- name == 'fgradInput' or name == 'finput' or
-- name == 'gradWeight' or name == 'gradBias') then
if (name == 'output' or name == 'gradInput' or
name == 'fgradInput' or name == 'finput') then
if torch.type(field) == 'table' then
val[name] = {}
else
val[name] = field.new()
end
end
if name == 'buffer' or name == 'buffer2' or name == 'normalized'
or name == 'centered' or name == 'addBuffer' then
val[name] = nil
end
end
end
return net
end
-------------------------------------------------------------------------
function nn_utils.tensorDimsStr (A)
if torch.isTensor(A) then
local tmp = A:size(1)
for iDim = 2,A:nDimension() do
tmp = tmp .. ' x ' .. A:size(iDim)
end
return tmp
else
local tmp = 'Length ' .. #A .. ' Table\n'
for i = 1, #A do
tmp = tmp .. 'Table[' .. i ..']: ' .. nn_utils.tensorDimsStr(A[i]) .. '\n'
end
return tmp
end
end
-- A multi-concat function.
-- Replaces the 'concat' in torch, which can't deal with cuda tensors
function nn_utils.concatTensors (tensors, outputDimension)
local nTensors = table.getn(tensors)
local sumOutputSizes = 0
for iTensor = 1,nTensors do
sumOutputSizes = sumOutputSizes + tensors[iTensor]:size(outputDimension)
end
local outputSize = tensors[1]:size()
outputSize[outputDimension] = sumOutputSizes
-- We clone and then resize to make sure it's the right kind of tensor.
-- TODO is there a better way to do this?
local res = tensors[1]:clone()
res:resize (outputSize)
local curOutputOffset = 1
for iTensor = 1,nTensors do
local accessor = {}
for j = 1,outputSize:size() do
accessor[j] = {}
end
local outputDimSize = tensors[iTensor]:size(outputDimension)
accessor[outputDimension] = {curOutputOffset, curOutputOffset + outputDimSize - 1}
res[accessor]:copy(tensors[iTensor])
curOutputOffset = curOutputOffset + outputDimSize
end
return res
end
function nn_utils.dumpNetwork (layer, inputData, prefix)
prefix = prefix or ''
local prefixExtension = " "
local output
local strLayer = tostring(layer)
if (strLayer:sub(1,13) == 'nn.Sequential') then
local nLayers = layer:size()
print (prefix .. 'Layer type: nn.Sequential (' .. nLayers .. ')')
print (prefix .. 'Input: ' .. nn_utils.tensorDimsStr(inputData))
local layerInput = inputData
for iLayer = 1,nLayers do
print (prefix .. 'Sequential layer ' .. iLayer)
local curLayer = layer:get(iLayer)
local res = nn_utils.dumpNetwork (curLayer, layerInput, prefix .. prefixExtension)
layerInput = res
end
output = layerInput
elseif (strLayer:sub(1,16) ~= "nn.ParallelTable" and strLayer:sub(1,11) == "nn.Parallel") then
local nLayers = table.getn(layer.modules)
print (prefix .. 'Layer type: nn.Parallel (' .. nLayers .. ')')
local inputDimension = layer.inputDimension
local outputDimension = layer.outputDimension
print (prefix .. 'Split on ' .. inputDimension)
print (prefix .. 'Input: ' .. nn_utils.tensorDimsStr(inputData))
local layerRes = {}
local sumOutputSizes = 0
for iLayer = 1,nLayers do
print (prefix .. 'Parallel layer ' .. iLayer)
local curLayer = layer:get(iLayer)
local curInput = inputData:select(inputDimension, iLayer)
local res = nn_utils.dumpNetwork (curLayer, curInput, prefix .. prefixExtension)
layerRes[iLayer] = res
end
output = nn_utils.concatTensors (layerRes, outputDimension)
else
print (prefix .. 'Layer type: ' .. strLayer)
print (prefix .. 'Input: ' .. nn_utils.tensorDimsStr(inputData))
output = layer:forward(inputData)
end
if torch.isTensor(output) and output:ne(output):sum() > 0 then
print( prefix .. '!!!!!!!!!!!!!!!!!!!!!!! Found NaN in output !!!!!!!!!!!!!!!!!!!!!!!')
end
print (prefix .. 'Output: ' .. nn_utils.tensorDimsStr(output))
return output
end
local function appendToPrefix (oldPrefix, newStuff)
if (oldPrefix and oldPrefix ~= '') then
return oldPrefix .. '_' .. newStuff;
else
return newStuff;
end
end
-- Assumes that the data matrix is set up as
-- level 1, channel 1
-- level 1, channel 2
-- ...
-- level 2, channel 1
-- level 2, channel 2
-- ...
function nn_utils.dumpIntermediateWeights (layer, inputData, pyramidLevelSizes, channelNames, outputImagesDir, filePrefix)
local output
local strLayer = tostring(layer)
if (strLayer:sub(1,13) == 'nn.Sequential') then
local nLayers = layer:size()
local layerInput = inputData
for iLayer = 1,nLayers do
local curLayer = layer:get(iLayer)
local newPrefix = appendToPrefix (filePrefix, 'layer' .. iLayer)
local res = nn_utils.dumpIntermediateWeights (curLayer, layerInput, pyramidLevelSizes, channelNames, outputImagesDir, newPrefix)
layerInput = res
end
output = layerInput
elseif (strLayer:sub(1,11) == "nn.Parallel") then
local nLayers = table.getn(layer.modules)
local inputDimension = layer.inputDimension
local outputDimension = layer.outputDimension
local combinedRes;
local nPyramidLevels = table.getn (pyramidLevelSizes)
local nChannels = table.getn (channelNames)
local layerRes = {}
assert (nLayers == nPyramidLevels * nChannels)
for iLevel = 1,nPyramidLevels do
for jChannel = 1,nChannels do
local iLayer = (iLevel-1) * nChannels + jChannel
local curLayer = layer:get(iLayer)
local curInput = inputData:select(inputDimension, iLayer)
local newPrefix = appendToPrefix (filePrefix, 'level' .. iLevel .. '_' .. channelNames[jChannel])
local res = nn_utils.dumpIntermediateWeights (curLayer, curInput, pyramidLevelSizes, channelNames, outputImagesDir, newPrefix)
layerRes[iLayer] = res
end
end
output = nn_utils.concatTensors (layerRes, outputDimension)
elseif (strLayer == "nn.SpatialConvolution" or
strLayer == "nn.SpatialConvolutionMM") then
-- For convolution layers, save out the weights and stuff:
local nInputPlane = layer["nInputPlane"]
local nOutputPlane = layer["nOutputPlane"]
local kw = layer["kW"]
local kh = layer["kH"]
local weightOrig = layer["weight"]
local w = torch.reshape (weightOrig, torch.LongStorage{nOutputPlane,nInputPlane,kw,kh})
local nChannels = table.getn (channelNames)
-- Only do this for the first layer:
if (w:size(2) == nChannels) then
local filename = appendToPrefix (filePrefix, '_weights.png')
image.save (paths.concat(outputImagesDir, filename),
image.toDisplayTensor {input=w:select(2,1), padding=3})
end
-- Only show the first 10 activations:
local nActivationImages = math.min (nOutputPlane, 10)
output = layer:forward(inputData)
for iOutputPlane = 1,nActivationImages do
local filename = appendToPrefix (filePrefix, '_activations_plane' .. iOutputPlane .. '.png')
image.save (paths.concat (outputImagesDir, filename),
image.toDisplayTensor {input=output[{{},iOutputPlane,{},{}}], padding=3})
end
elseif (strLayer == 'nn.View') then
output = layer:forward(inputData)
if (output:nDimension() == 4 and output:size(2) == 1) then
local filename = appendToPrefix (filePrefix, '_view.png')
image.save (paths.concat (outputImagesDir, filename),
image.toDisplayTensor {input=output[{{},1,{},{}}], padding=0})
end
else
output = layer:forward(inputData)
end
return output
end
function nn_utils.customLCN(inputs, kernel, threshold, thresval)
assert (inputs:dim() == 4, "Input should be of the form nSamples x nChannels x width x height")
local padH = math.floor(kernel:size(1)/2)
local padW = padH
-- normalize the kernel
kernel:div(kernel:sum())
local meanestimator = nn.Sequential()
meanestimator:add(nn.SpatialZeroPadding(padW, padW, padH, padH))
meanestimator:add(nn.SpatialConvolutionMap(nn.tables.oneToOne(1), kernel:size(1), 1))
meanestimator:add(nn.SpatialConvolution(1, 1, 1, kernel:size(1), 1))
local stdestimator = nn.Sequential()
stdestimator:add(nn.Square())
stdestimator:add(nn.SpatialZeroPadding(padW, padW, padH, padH))
stdestimator:add(nn.SpatialConvolutionMap(nn.tables.oneToOne(1), kernel:size(1), 1))
stdestimator:add(nn.SpatialConvolution(1, 1, 1, kernel:size(1)))
stdestimator:add(nn.Sqrt())
for i = 1,1 do
meanestimator.modules[2].weight[i]:copy(kernel)
meanestimator.modules[3].weight[1][i]:copy(kernel)
stdestimator.modules[3].weight[i]:copy(kernel)
stdestimator.modules[4].weight[1][i]:copy(kernel)
end
meanestimator.modules[2].bias:zero()
meanestimator.modules[3].bias:zero()
stdestimator.modules[3].bias:zero()
stdestimator.modules[4].bias:zero()
-- Run the meanestimator on a bunch of ones to figure out the sum of the kenrel
-- (This is pretty wasteful for large number of samples N of Nx1xKxK.)
local coef = meanestimator:updateOutput(inputs.new():resizeAs(inputs):fill(1))
coef = coef:clone()
-- Take the kernel weighted local sums
local localSums = meanestimator:updateOutput(inputs)
-- Divide by the response of the kernel on ones (effectively, dividing by the kernel sum)
local adjustedSums = nn.CDivTable():updateOutput{localSums, coef}
-- Subtract tout the kernel weigthed adjusted sums
local meanSubtracted = nn.CSubTable():updateOutput{inputs, adjustedSums}
-- Take the mean subtracted output and divide out the kernel weighted standard deviation
local localStds = stdestimator:updateOutput(meanSubtracted)
local adjustedStds = nn.CDivTable():updateOutput{localStds, coef}
local thresholdedStds = nn.Threshold(threshold, thresval):updateOutput(adjustedStds)
local outputs = nn.CDivTable():updateOutput{meanSubtracted, thresholdedStds}
return outputs
end
function nn_utils.originalLCN(inputs, kernel, threshold, thresval)
local normalization = nn.SpatialContrastiveNormalization(1, kernel, threshold, thresval)
local outputs = inputs:clone()
for i=1,inputs:size(1) do
outputs[i] = normalization:forward(inputs[i])
xlua.progress(i, inputs:size(1))
end
return outputs
end
function nn_utils.testLCN()
local neighborhood = image.gaussian1D(7)
local inputs = torch.randn(100, 1, 50, 50)
local timer = torch.Timer()
timer:reset()
local originalOutputs = nn_utils.originalLCN(inputs, neighborhood, 1, 1)
print('Original LCN took : ' .. timer:time().real .. ' seconds')
timer:reset()
local customOutputs = nn_utils.customLCN(inputs, neighborhood, 1, 1)
print(' Custom LCN took : ' .. timer:time().real .. ' seconds')
local norm = (customOutputs - originalOutputs):norm()
print('Difference between original and custom LCN implementations : '..norm)
end
local function ConvInit(model, name)
for k, v in pairs(model:findModules(name)) do
local n = v.kW * v.kH * v.nOutputPlane
v.weight:normal(0, math.sqrt(2 / n))
if cudnn.version >= 4000 then
v.bias = nil
v.gradBias = nil
else
v.bias:zero()
end
end
end
local function BNInit(model, name)
for k, v in pairs(model:findModules(name)) do
v.weight:fill(1)
v.bias:zero()
end
end
function nn_utils.init(model, opt)
ConvInit(model, 'cudnn.SpatialConvolution')
ConvInit(model, 'nn.SpatialConvolution')
BNInit(model, 'fbnn.SpatialBatchNormalization')
BNInit(model, 'cudnn.SpatialBatchNormalization')
BNInit(model, 'nn.SpatialBatchNormalization')
for k, v in pairs(model:findModules('nn.Linear')) do
v.bias:zero()
end
end
function nn_utils.cudnnize(model, opt)
model:cuda()
cudnn.convert(model, cudnn)
if opt.cudnn == 'deterministic' then
model:apply(function(m)
if m.setMode then m:setMode(1,1,1) end
end)
end
end
return nn_utils