Last active
October 29, 2017 20:47
-
-
Save vadimkantorov/91bb2532da47eaf70255 to your computer and use it in GitHub Desktop.
A routine to convert some MatConvNet layers to Torch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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