|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function nn_utils.normalize(im, width, height, nmean)
|
|
|
nmean = nmean or nn_utils.nmean
|
|
|
assert((#im)[1] == (#nmean)[1])
|
|
|
|
|
|
|
|
|
local normalized = image.scale(im, width, height)
|
|
|
|
|
|
|
|
|
if normalized:max() > 1 then
|
|
|
normalized:div(255)
|
|
|
end
|
|
|
|
|
|
|
|
|
for i = 1, (#nmean)[1] do
|
|
|
normalized[i]:csub(nmean[i])
|
|
|
end
|
|
|
|
|
|
return normalized
|
|
|
end
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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') 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
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
|
|
local coef = meanestimator:updateOutput(inputs.new():resizeAs(inputs):fill(1))
|
|
|
coef = coef:clone()
|
|
|
|
|
|
|
|
|
local localSums = meanestimator:updateOutput(inputs)
|
|
|
|
|
|
local adjustedSums = nn.CDivTable():updateOutput{localSums, coef}
|
|
|
|
|
|
local meanSubtracted = nn.CSubTable():updateOutput{inputs, adjustedSums}
|
|
|
|
|
|
|
|
|
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
|
|
|
|