Skip to content

Commit

Permalink
[layer model] remove duplicated init ops
Browse files Browse the repository at this point in the history
it saves some model init time, and reduce confusion.
  • Loading branch information
xianjiec authored and houseroad committed Mar 28, 2018
1 parent d5e38a8 commit 078b6d5
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 23 deletions.
20 changes: 6 additions & 14 deletions caffe2/python/layer_model_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from __future__ import print_function
from __future__ import unicode_literals

from caffe2.python import core, model_helper, schema, scope
from caffe2.python import core, model_helper, schema, scope, utils
from caffe2.python.modeling.parameter_info import (
ParameterInfo,
)
Expand Down Expand Up @@ -164,17 +164,6 @@ def maybe_add_global_constant(self, name, *args, **kwargs):
# if the name was already registered in global_constants, it will not be
# added even if the intended value is different from its original value

def op_equal(operator1, operator2):
o1 = copy.deepcopy(operator1)
o2 = copy.deepcopy(operator2)
# debug_info is supposed to be different, and we don't need to
# compare debug_info
if hasattr(o1, 'debug_info'):
o1.debug_info = ''
if hasattr(o2, 'debug_info'):
o2.debug_info = ''
return o1 == o2

if name in self.global_constants:
blob_name = self.global_constants[name]
initializer_op = \
Expand All @@ -183,8 +172,11 @@ def op_equal(operator1, operator2):
)
# check if the original initializer is the same as the one intended
# now
assert op_equal(initializer_op,
self.global_constant_initializers[blob_name]), \
assert utils.OpAlmostEqual(
initializer_op,
self.global_constant_initializers[blob_name],
'debug_info'
), \
"conflict initializers for global constant %s, " \
"previous %s, now %s" % (
blob_name, str(initializer_op),
Expand Down
31 changes: 30 additions & 1 deletion caffe2/python/layer_parameter_sharing_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import print_function
from __future__ import unicode_literals

from caffe2.python import scope
from caffe2.python import core, scope
from caffe2.python.modeling.parameter_sharing import (
ParameterSharing,
)
Expand Down Expand Up @@ -119,3 +119,32 @@ def test_layer_shared_parameter_name_different_shapes(self):
self.model.input_feature_schema.float_features,
output_dims + 1
)

def test_layer_duplicated_parameter_init(self):
output_dims = 2
with scope.NameScope('global_scope'):
with ParameterSharing({'new_fc': 'shared_fc'}):
self.model.FC(
self.model.input_feature_schema.float_features,
output_dims,
name='shared_fc'
)
self.model.FC(
self.model.input_feature_schema.float_features,
output_dims,
name='new_fc'
)

train_init_net = core.Net('train_init_net')
train_net = core.Net('train_net')
for layer in self.model.layers:
layer.add_operators(train_net, train_init_net)
op_outputs = []
for op in train_init_net._net.op:
op_outputs.extend(op.output)

# only fill these parameter blobs once
self.assertEquals(
sorted(op_outputs),
['global_scope/shared_fc/b', 'global_scope/shared_fc/w']
)
25 changes: 17 additions & 8 deletions caffe2/python/layers/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from __future__ import unicode_literals

import logging
from caffe2.python import core, schema, scope, workspace

from caffe2.python import core, schema, scope, utils, workspace
from caffe2.python.layers.tags import TagContext
from caffe2.proto import caffe2_pb2

Expand Down Expand Up @@ -310,13 +311,21 @@ def add_init_params(self, init_net):
# so extend is used
init_op = param.initializer
current_device_scope = scope.CurrentDeviceScope()
if init_op:
if not init_op.HasField('device_option') and\
current_device_scope:
init_op = caffe2_pb2.OperatorDef()
init_op.CopyFrom(param.initializer)
init_op.device_option.CopyFrom(current_device_scope)
init_net._net.op.extend([init_op])
if not init_op:
continue

if not init_op.HasField('device_option') and\
current_device_scope:
init_op = caffe2_pb2.OperatorDef()
init_op.CopyFrom(param.initializer)
init_op.device_option.CopyFrom(current_device_scope)

# do not add duplicated init ops
if any(utils.OpAlmostEqual(op, init_op, 'debug_info')
for op in init_net._net.op):
continue

init_net._net.op.extend([init_op])

def create_param(self, param_name, shape, initializer, optimizer,
ps_param=None, regularizer=None):
Expand Down
28 changes: 28 additions & 0 deletions caffe2/python/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,43 @@
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from caffe2.proto import caffe2_pb2
from future.utils import viewitems
from google.protobuf.message import DecodeError, Message
from google.protobuf import text_format

import sys
import copy
import collections
import functools
import numpy as np
from six import integer_types, binary_type, text_type


def OpAlmostEqual(op_a, op_b, ignore_fields=None):
'''
Two ops are identical except for each field in the `ignore_fields`.
'''
ignore_fields = ignore_fields or []
if not isinstance(ignore_fields, list):
ignore_fields = [ignore_fields]

assert all(isinstance(f, text_type) for f in ignore_fields), (
'Expect each field is text type, but got {}'.format(ignore_fields))

def clean_op(op):
op = copy.deepcopy(op)
for field in ignore_fields:
if op.HasField(field):
op.ClearField(field)
return op

op_a = clean_op(op_a)
op_b = clean_op(op_b)
return op_a == op_b


def CaffeBlobToNumpyArray(blob):
if (blob.num != 0):
# old style caffe blob.
Expand Down Expand Up @@ -275,10 +301,12 @@ def run(cls, func):
sys.exit(1)
raise


def raiseIfNotEqual(a, b, msg):
if a != b:
raise Exception("{}. {} != {}".format(msg, a, b))


def debug(f):
'''
Use this method to decorate your function with DebugMode's functionality
Expand Down

0 comments on commit 078b6d5

Please sign in to comment.