Skip to content

Instantly share code, notes, and snippets.

@vadimkantorov
Last active October 29, 2017 20:47
Show Gist options
  • Save vadimkantorov/91bb2532da47eaf70255 to your computer and use it in GitHub Desktop.
Save vadimkantorov/91bb2532da47eaf70255 to your computer and use it in GitHub Desktop.
A routine to convert some MatConvNet layers to Torch
-- example for an AlexNet-like model
--model, unconverted = loadmatconvnet('/path/to/somemodel.mat', {
-- conv2 = {groups = 2},
-- conv4 = {groups = 2},
-- conv5 = {groups = 2},
-- fc6 = {fc_kH = 6, fc_kW = 6, type = 'nn.Linear'}, --ONE MAY NEED TO BE CAREFUL, these fc_kH, fc_kW are for 1x36 (or 36x1, don't remember) saved weights
-- fc7 = {type = 'nn.Linear'},
--})
matio = require 'matio'
function loadmatconvnet(path, config)
config = config or {}
local converters = {
conv = function(layer)
assert(layer.pad[1][1] == layer.pad[1][2] and layer.pad[1][3] == layer.pad[1][4])
local c = config[layer.name:storage():string()] or {}
local dH, dW = layer.stride[1][1], layer.stride[1][2]
local padH, padW = layer.pad[1][1], layer.pad[1][3]
local weight, bias = layer.weights[1], layer.weights[2]
local kH, kW = c['fc_kH'] or weight:size(1), c['fc_kW'] or weight:size(2)
local groups = c['groups'] or 1
if c['fc_kH'] or c['fc_kW'] then
weight = weight:contiguous():view(c['fc_kW'], c['fc_kH'], weight:size(3), weight:size(4)):transpose(1, 2)
end
local nInputPlane, nOutputPlane = weight:size(3), weight:size(4)
nInputPlane = nInputPlane * groups
local module = c['type'] == 'nn.Linear' and nn.Linear(nInputPlane * kW * kH, nOutputPlane) or cudnn.SpatialConvolution(nInputPlane, nOutputPlane, kW, kH, dW, dH, padW, padH, groups)
module.weight:copy(weight:permute(4,3,1,2)) -- H x W x numInputPlane x numOutputPlane -> numOutputPlane x numInputPlane x H x W
module.bias:copy(bias)
return module
end,
relu = function(layer)
assert(layer.leak == nil)
return cudnn.ReLU(false)
end,
pool = function(layer)
assert(layer.pad[1][1] == layer.pad[1][2] and layer.pad[1][3] == layer.pad[1][4])
local pooler = ({max = cudnn.SpatialMaxPooling, avg = cudnn.SpatialAveragePooling})[layer.method:storage():string()]
local kH, kW = layer.pool[1][1], layer.pool[1][2]
local dH, dW = layer.stride[1][1], layer.stride[1][2]
local padH, padW = layer.pad[1][1], layer.pad[1][3]
return pooler(kW, kH, dW, dH, padW, padH):floor()
end,
normalize = function(layer)
local size, kappa, alpha, beta = layer.param[1][1], layer.param[1][2], layer.param[1][3], layer.param[1][4]
--th> l.net.layers[4].param 5.0000e+00 1.0000e+00 2.0000e-05 7.5000e-01
--// This function will set lrnN=5, lrnAlpha=1e-4, lrnBeta=0.75, lrnK=2.0 as defaults from Krizhevsky'12 ImageNet paper
return cudnn.SpatialCrossMapLRN(size, alpha * size, beta, kappa)
end,
}
local l = matio.load(path)
local model = nn.Sequential()
local unconverted = {}
for i, layer in ipairs((l.layers and l.layers[1]) or l.net.layers) do
local converter = converters[layer.type:storage():string()]
if converter then
local module = converter(layer)
module.name = layer.name:storage():string()
model:add(module)
print(i, module.name, module)
else
local module = layer
module.name = layer.name:storage():string()
module.type = layer.type:storage():string()
table.insert(unconverted, module)
print(i, module.name, 'unconverted')
end
end
return model, unconverted
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment