| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- ## @package conv
- # Module caffe2.python.helpers.conv
- from caffe2.python import core
- from caffe2.python.modeling import initializers
- from caffe2.python.modeling.parameter_info import ParameterTags
- def _ConvBase(
- model,
- is_nd,
- blob_in,
- blob_out,
- dim_in,
- dim_out,
- kernel,
- weight_init=None,
- bias_init=None,
- WeightInitializer=None,
- BiasInitializer=None,
- group=1,
- transform_inputs=None,
- use_cudnn=False,
- order="NCHW",
- cudnn_exhaustive_search=False,
- ws_nbytes_limit=None,
- float16_compute=False,
- **kwargs
- ):
- kernels = []
- if is_nd:
- if not isinstance(kernel, list):
- kernels = [kernel]
- else:
- kernels = kernel
- else:
- if isinstance(kernel, list):
- assert len(kernel) == 2, "Conv support only a 2D kernel."
- kernels = kernel
- else:
- kernels = [kernel] * 2
- requested_engine = kwargs.get('engine')
- if requested_engine is not None:
- if use_cudnn and requested_engine != 'CUDNN':
- raise ValueError(
- 'When use_cudnn=True, the only engine you can specify is '
- '"CUDNN"')
- elif not use_cudnn and requested_engine == 'CUDNN':
- raise ValueError(
- 'When use_cudnn=False, the only engine you can specify is '
- '""')
- if use_cudnn:
- kwargs['engine'] = 'CUDNN'
- kwargs['exhaustive_search'] = cudnn_exhaustive_search
- if ws_nbytes_limit:
- kwargs['ws_nbytes_limit'] = ws_nbytes_limit
- use_bias =\
- False if ("no_bias" in kwargs and kwargs["no_bias"]) else True
- blob_out = blob_out or model.net.NextName()
- weight_shape = [dim_out]
- if order == "NCHW":
- weight_shape.append(int(dim_in / group))
- weight_shape.extend(kernels)
- else:
- weight_shape.extend(kernels)
- weight_shape.append(int(dim_in / group))
- WeightInitializer = initializers.update_initializer(
- WeightInitializer, weight_init, ("XavierFill", {})
- )
- BiasInitializer = initializers.update_initializer(
- BiasInitializer, bias_init, ("ConstantFill", {})
- )
- if not model.init_params:
- WeightInitializer = initializers.ExternalInitializer()
- BiasInitializer = initializers.ExternalInitializer()
- weight = model.create_param(
- param_name=blob_out + '_w',
- shape=weight_shape,
- initializer=WeightInitializer,
- tags=ParameterTags.WEIGHT
- )
- if use_bias:
- bias = model.create_param(
- param_name=blob_out + '_b',
- shape=[dim_out, ],
- initializer=BiasInitializer,
- tags=ParameterTags.BIAS
- )
- if use_bias:
- inputs = [blob_in, weight, bias]
- else:
- inputs = [blob_in, weight]
- if transform_inputs is not None:
- transform_inputs(model, blob_out, inputs)
- # Enable float 16 compute kernel (relevant for CUDA)
- if float16_compute:
- kwargs['float16_compute'] = True
- # For the operator, we no longer need to provide the no_bias field
- # because it can automatically figure this out from the number of
- # inputs.
- if 'no_bias' in kwargs:
- del kwargs['no_bias']
- if group != 1:
- kwargs['group'] = group
- if is_nd:
- return model.net.Conv(
- inputs,
- blob_out,
- kernels=kernels,
- order=order,
- **kwargs)
- else:
- if isinstance(kernel, list):
- return model.net.Conv(
- inputs,
- blob_out,
- kernel_h=kernel[0],
- kernel_w=kernel[1],
- order=order,
- **kwargs)
- else:
- return model.net.Conv(
- inputs,
- blob_out,
- kernel=kernel,
- order=order,
- **kwargs)
- def conv_nd(
- model,
- blob_in,
- blob_out,
- dim_in,
- dim_out,
- kernel,
- weight_init=None,
- bias_init=None,
- WeightInitializer=None,
- BiasInitializer=None,
- group=1,
- transform_inputs=None,
- order="NCHW",
- **kwargs
- ):
- """N-dimensional convolution for inputs with NCHW storage order.
- """
- assert order == "NCHW", "ConvNd only supported for NCHW storage."
- return _ConvBase(model, True, blob_in, blob_out, dim_in, dim_out, kernel,
- weight_init, bias_init, WeightInitializer, BiasInitializer,
- group, transform_inputs, order=order, **kwargs)
- def conv(
- model,
- blob_in,
- blob_out,
- dim_in,
- dim_out,
- kernel,
- weight_init=None,
- bias_init=None,
- WeightInitializer=None,
- BiasInitializer=None,
- group=1,
- transform_inputs=None,
- **kwargs
- ):
- """2-dimensional convolution.
- """
- return _ConvBase(model, False, blob_in, blob_out, dim_in, dim_out, kernel,
- weight_init, bias_init, WeightInitializer, BiasInitializer,
- group, transform_inputs, **kwargs)
- def conv_transpose(
- model,
- blob_in,
- blob_out,
- dim_in,
- dim_out,
- kernel,
- weight_init=None,
- bias_init=None,
- use_cudnn=False,
- order="NCHW",
- cudnn_exhaustive_search=False,
- ws_nbytes_limit=None,
- **kwargs
- ):
- """ConvTranspose.
- """
- weight_init = weight_init if weight_init else ('XavierFill', {})
- bias_init = bias_init if bias_init else ('ConstantFill', {})
- blob_out = blob_out or model.net.NextName()
- weight_shape = (
- [dim_in, dim_out, kernel, kernel]
- if order == "NCHW" else [dim_in, kernel, kernel, dim_out]
- )
- if model.init_params:
- weight = model.param_init_net.__getattr__(weight_init[0])(
- [],
- blob_out + '_w',
- shape=weight_shape,
- **weight_init[1]
- )
- bias = model.param_init_net.__getattr__(bias_init[0])(
- [],
- blob_out + '_b',
- shape=[dim_out, ],
- **bias_init[1]
- )
- else:
- weight = core.ScopedBlobReference(
- blob_out + '_w', model.param_init_net)
- bias = core.ScopedBlobReference(
- blob_out + '_b', model.param_init_net)
- model.AddParameter(weight, ParameterTags.WEIGHT)
- model.AddParameter(bias, ParameterTags.BIAS)
- if use_cudnn:
- kwargs['engine'] = 'CUDNN'
- kwargs['exhaustive_search'] = cudnn_exhaustive_search
- if ws_nbytes_limit:
- kwargs['ws_nbytes_limit'] = ws_nbytes_limit
- return model.net.ConvTranspose(
- [blob_in, weight, bias],
- blob_out,
- kernel=kernel,
- order=order,
- **kwargs
- )
- def group_conv(
- model,
- blob_in,
- blob_out,
- dim_in,
- dim_out,
- kernel,
- weight_init=None,
- bias_init=None,
- group=1,
- **kwargs
- ):
- """Group Convolution.
- This is essentially the same as Conv with a group argument passed in.
- We specialize this for backward interface compatibility.
- """
- return conv(model, blob_in, blob_out, dim_in, dim_out, kernel,
- weight_init=weight_init, bias_init=bias_init,
- group=group, **kwargs)
- def group_conv_deprecated(
- model,
- blob_in,
- blob_out,
- dim_in,
- dim_out,
- kernel,
- weight_init=None,
- bias_init=None,
- group=1,
- use_cudnn=False,
- order="NCHW",
- cudnn_exhaustive_search=False,
- ws_nbytes_limit=None,
- **kwargs
- ):
- """GroupConvolution's deprecated interface.
- This is used to simulate a group convolution via split and concat. You
- should always use the new group convolution in your new code.
- """
- weight_init = weight_init if weight_init else ('XavierFill', {})
- bias_init = bias_init if bias_init else ('ConstantFill', {})
- use_bias = False if ("no_bias" in kwargs and kwargs["no_bias"]) else True
- if use_cudnn:
- kwargs['engine'] = 'CUDNN'
- kwargs['exhaustive_search'] = cudnn_exhaustive_search
- if ws_nbytes_limit:
- kwargs['ws_nbytes_limit'] = ws_nbytes_limit
- if dim_in % group:
- raise ValueError("dim_in should be divisible by group.")
- if dim_out % group:
- raise ValueError("dim_out should be divisible by group.")
- splitted_blobs = model.net.DepthSplit(
- blob_in,
- ['_' + blob_out + '_gconv_split_' + str(i) for i in range(group)],
- dimensions=[int(dim_in / group) for i in range(group)],
- order=order
- )
- weight_shape = (
- [dim_out / group, dim_in / group, kernel, kernel]
- if order == "NCHW" else
- [dim_out / group, kernel, kernel, dim_in / group]
- )
- # Make sure that the shapes are of int format. Especially for py3 where
- # int division gives float output.
- weight_shape = [int(v) for v in weight_shape]
- conv_blobs = []
- for i in range(group):
- if model.init_params:
- weight = model.param_init_net.__getattr__(weight_init[0])(
- [],
- blob_out + '_gconv_%d_w' % i,
- shape=weight_shape,
- **weight_init[1]
- )
- if use_bias:
- bias = model.param_init_net.__getattr__(bias_init[0])(
- [],
- blob_out + '_gconv_%d_b' % i,
- shape=[int(dim_out / group)],
- **bias_init[1]
- )
- else:
- weight = core.ScopedBlobReference(
- blob_out + '_gconv_%d_w' % i, model.param_init_net)
- if use_bias:
- bias = core.ScopedBlobReference(
- blob_out + '_gconv_%d_b' % i, model.param_init_net)
- model.AddParameter(weight, ParameterTags.WEIGHT)
- if use_bias:
- model.AddParameter(bias, ParameterTags.BIAS)
- if use_bias:
- inputs = [weight, bias]
- else:
- inputs = [weight]
- if 'no_bias' in kwargs:
- del kwargs['no_bias']
- conv_blobs.append(
- splitted_blobs[i].Conv(
- inputs,
- blob_out + '_gconv_%d' % i,
- kernel=kernel,
- order=order,
- **kwargs
- )
- )
- concat, concat_dims = model.net.Concat(
- conv_blobs,
- [blob_out,
- "_" + blob_out + "_concat_dims"],
- order=order
- )
- return concat
|