blob: a8512106c59cd1fb0911cb86089e4ad2275c498f [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
'''Extract the net parameters from the torch file and store them as python dict
using cPickle'''
import os
import torchfile
import numpy as np
from argparse import ArgumentParser
import model
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
verbose=False
def add_param(idx, name, val, params):
if type(params) == dict:
assert name not in params, 'duplicated param %s' % name
params[name] = val
else:
assert params[idx].size() == val.size,\
'size mismatch for %s: %s - %s'\
% (name, (params[idx].shape,), (val.shape,))
params[idx].copy_from_numpy(val)
if verbose:
print(name, val.shape)
def conv(m, idx, params, param_names):
outplane = m['weight'].shape[0]
name = param_names[idx]
val = np.reshape(m['weight'], (outplane, -1))
add_param(idx, name, val, params)
return idx + 1
def batchnorm(m, idx, params, param_names):
add_param(idx, param_names[idx], m['weight'], params)
add_param(idx + 1, param_names[idx + 1], m['bias'], params)
add_param(idx + 2, param_names[idx + 2], m['running_mean'], params)
add_param(idx + 3, param_names[idx + 3], m['running_var'], params)
return idx + 4
def linear(m, idx, params, param_names):
add_param(idx, param_names[idx], np.transpose(m['weight']), params)
add_param(idx + 1, param_names[idx + 1], m['bias'], params)
return idx + 2
def traverse(m, idx, params, param_names):
''' Traverse all modules of the torch checkpoint file to extract params.
Args:
m, a TorchObject
idx, index for the current cursor of param_names
params, an empty dictionary (name->numpy) to dump the params via pickle;
or a list of tensor objects which should be in the same order as
param_names, called to initialize net created in SINGA directly
using param values from torch checkpoint file.
Returns:
the updated idx
'''
module_type = m.__dict__['_typename']
if module_type in ['nn.Sequential', 'nn.ConcatTable'] :
for x in m.modules:
idx = traverse(x, idx, params, param_names)
elif 'SpatialConvolution' in module_type:
idx = conv(m, idx, params, param_names)
elif 'SpatialBatchNormalization' in module_type:
idx = batchnorm(m, idx, params, param_names)
elif 'Linear' in module_type:
idx = linear(m, idx, params, param_names)
return idx
if __name__ == '__main__':
parser = ArgumentParser(description='Convert params from torch to python '
'dict. \n resnet could have depth of 18, 34, 101, 152; \n'
'wrn has depth 50; preact has depth 200; addbn has depth 50')
parser.add_argument("infile", help="torch checkpoint file")
parser.add_argument("model", choices=['resnet', 'wrn', 'preact', 'addbn'])
parser.add_argument("depth", type=int, choices=[18, 34, 50, 101, 152, 200])
args = parser.parse_args()
net = model.create_net(args.model, args.depth)
# model.init_params(net)
m = torchfile.load(args.infile)
params = {}
# params = net.param_values()
param_names = net.param_names()
traverse(m, 0, params, param_names)
miss = [name for name in param_names if name not in params]
if len(miss) > 0:
print('The following params are missing from torch file')
print(miss)
outfile = os.path.splitext(args.infile)[0] + '.pickle'
with open(outfile, 'wb') as fd:
pickle.dump(params, fd)