normalization.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. ## @package normalization
  2. # Module caffe2.python.helpers.normalization
  3. from caffe2.python import scope
  4. from caffe2.python.modeling.parameter_info import ParameterTags
  5. from caffe2.proto import caffe2_pb2
  6. from caffe2.python.modeling import initializers
  7. def lrn(model, blob_in, blob_out, order="NCHW", use_cudnn=False, **kwargs):
  8. """LRN"""
  9. dev = kwargs['device_option'] if 'device_option' in kwargs \
  10. else scope.CurrentDeviceScope()
  11. is_cpu = dev is None or dev.device_type == caffe2_pb2.CPU
  12. if use_cudnn and (not is_cpu):
  13. kwargs['engine'] = 'CUDNN'
  14. blobs_out = blob_out
  15. else:
  16. blobs_out = [blob_out, "_" + blob_out + "_scale"]
  17. lrn = model.net.LRN(
  18. blob_in,
  19. blobs_out,
  20. order=order,
  21. **kwargs
  22. )
  23. if use_cudnn and (not is_cpu):
  24. return lrn
  25. else:
  26. return lrn[0]
  27. def softmax(model, blob_in, blob_out=None, use_cudnn=False, **kwargs):
  28. """Softmax."""
  29. if use_cudnn:
  30. kwargs['engine'] = 'CUDNN'
  31. if blob_out is not None:
  32. return model.net.Softmax(blob_in, blob_out, **kwargs)
  33. else:
  34. return model.net.Softmax(blob_in, **kwargs)
  35. def instance_norm(model, blob_in, blob_out, dim_in, order="NCHW", **kwargs):
  36. blob_out = blob_out or model.net.NextName()
  37. # Input: input, scale, bias
  38. # Output: output, saved_mean, saved_inv_std
  39. # scale: initialize with ones
  40. # bias: initialize with zeros
  41. def init_blob(value, suffix):
  42. return model.param_init_net.ConstantFill(
  43. [], blob_out + "_" + suffix, shape=[dim_in], value=value)
  44. scale, bias = init_blob(1.0, "s"), init_blob(0.0, "b")
  45. model.AddParameter(scale, ParameterTags.WEIGHT)
  46. model.AddParameter(bias, ParameterTags.BIAS)
  47. blob_outs = [blob_out, blob_out + "_sm", blob_out + "_siv"]
  48. if 'is_test' in kwargs and kwargs['is_test']:
  49. blob_outputs = model.net.InstanceNorm(
  50. [blob_in, scale, bias], [blob_out],
  51. order=order, **kwargs)
  52. return blob_outputs
  53. else:
  54. blob_outputs = model.net.InstanceNorm(
  55. [blob_in, scale, bias], blob_outs,
  56. order=order, **kwargs)
  57. # Return the output
  58. return blob_outputs[0]
  59. def spatial_bn(model, blob_in, blob_out, dim_in,
  60. init_scale=1., init_bias=0.,
  61. ScaleInitializer=None, BiasInitializer=None,
  62. RunningMeanInitializer=None, RunningVarianceInitializer=None,
  63. order="NCHW", **kwargs):
  64. blob_out = blob_out or model.net.NextName()
  65. # Input: input, scale, bias, est_mean, est_inv_var
  66. # Output: output, running_mean, running_inv_var, saved_mean,
  67. # saved_inv_var
  68. # scale: initialize with init_scale (default 1.)
  69. # bias: initialize with init_bias (default 0.)
  70. # est mean: zero
  71. # est var: ones
  72. if model.init_params:
  73. scale_init = ("ConstantFill", {'value': init_scale})
  74. bias_init = ("ConstantFill", {'value': init_bias})
  75. rm_init = ("ConstantFill", {'value': 0.0})
  76. riv_init = ("ConstantFill", {'value': 1.0})
  77. ScaleInitializer = initializers.update_initializer(
  78. ScaleInitializer, scale_init, ("ConstantFill", {})
  79. )
  80. BiasInitializer = initializers.update_initializer(
  81. BiasInitializer, bias_init, ("ConstantFill", {})
  82. )
  83. RunningMeanInitializer = initializers.update_initializer(
  84. RunningMeanInitializer, rm_init, ("ConstantFill", {})
  85. )
  86. RunningVarianceInitializer = initializers.update_initializer(
  87. RunningVarianceInitializer, riv_init, ("ConstantFill", {})
  88. )
  89. else:
  90. ScaleInitializer = initializers.ExternalInitializer()
  91. BiasInitializer = initializers.ExternalInitializer()
  92. RunningMeanInitializer = initializers.ExternalInitializer()
  93. RunningVarianceInitializer = initializers.ExternalInitializer()
  94. scale = model.create_param(
  95. param_name=blob_out + '_s',
  96. shape=[dim_in],
  97. initializer=ScaleInitializer,
  98. tags=ParameterTags.WEIGHT
  99. )
  100. bias = model.create_param(
  101. param_name=blob_out + '_b',
  102. shape=[dim_in],
  103. initializer=BiasInitializer,
  104. tags=ParameterTags.BIAS
  105. )
  106. running_mean = model.create_param(
  107. param_name=blob_out + '_rm',
  108. shape=[dim_in],
  109. initializer=RunningMeanInitializer,
  110. tags=ParameterTags.COMPUTED_PARAM
  111. )
  112. running_inv_var = model.create_param(
  113. param_name=blob_out + '_riv',
  114. shape=[dim_in],
  115. initializer=RunningVarianceInitializer,
  116. tags=ParameterTags.COMPUTED_PARAM
  117. )
  118. blob_outs = [blob_out, running_mean, running_inv_var,
  119. blob_out + "_sm", blob_out + "_siv"]
  120. if 'is_test' in kwargs and kwargs['is_test']:
  121. blob_outputs = model.net.SpatialBN(
  122. [blob_in, scale, bias, blob_outs[1], blob_outs[2]], [blob_out],
  123. order=order, **kwargs)
  124. return blob_outputs
  125. else:
  126. blob_outputs = model.net.SpatialBN(
  127. [blob_in, scale, bias, blob_outs[1], blob_outs[2]], blob_outs,
  128. order=order, **kwargs)
  129. # Return the output
  130. return blob_outputs[0]
  131. def spatial_gn(model, blob_in, blob_out, dim_in,
  132. init_scale=1., init_bias=0.,
  133. ScaleInitializer=None, BiasInitializer=None,
  134. RunningMeanInitializer=None, RunningVarianceInitializer=None,
  135. order="NCHW", **kwargs):
  136. '''
  137. Group normalizes the input, cf. https://arxiv.org/abs/1803.08494.
  138. '''
  139. blob_out = blob_out or model.net.NextName()
  140. # Input: input, scale, bias
  141. # Output: output, group_mean, group_inv_std
  142. # scale: initialize with init_scale (default 1.)
  143. # [recommendation: set init_scale = 0. in the last layer for each res block]
  144. # bias: initialize with init_bias (default 0.)
  145. if model.init_params:
  146. scale_init = ("ConstantFill", {'value': init_scale})
  147. bias_init = ("ConstantFill", {'value': init_bias})
  148. ScaleInitializer = initializers.update_initializer(
  149. ScaleInitializer, scale_init, ("ConstantFill", {})
  150. )
  151. BiasInitializer = initializers.update_initializer(
  152. BiasInitializer, bias_init, ("ConstantFill", {})
  153. )
  154. else:
  155. ScaleInitializer = initializers.ExternalInitializer()
  156. BiasInitializer = initializers.ExternalInitializer()
  157. scale = model.create_param(
  158. param_name=blob_out + '_s',
  159. shape=[dim_in],
  160. initializer=ScaleInitializer,
  161. tags=ParameterTags.WEIGHT
  162. )
  163. bias = model.create_param(
  164. param_name=blob_out + '_b',
  165. shape=[dim_in],
  166. initializer=BiasInitializer,
  167. tags=ParameterTags.BIAS
  168. )
  169. blob_outs = [blob_out,
  170. blob_out + "_mean", blob_out + "_std"]
  171. blob_outputs = model.net.GroupNorm(
  172. [blob_in, scale, bias],
  173. blob_outs,
  174. **kwargs)
  175. # Return the output
  176. return blob_outputs[0]
  177. def layer_norm(
  178. model,
  179. blob_in,
  180. blob_out,
  181. dim_in,
  182. axis=1,
  183. epsilon=1e-4,
  184. initial_scale=1.0,
  185. initial_bias=0.0,
  186. ):
  187. '''
  188. Layer normalizes the input, cf. https://arxiv.org/pdf/1607.06450.pdf.
  189. Args:
  190. blob_in: The input blob to layer normalize.
  191. blob_out: The layer normalized output blob.
  192. dim_in: The dimension of the scale and bias. For example, if blob_in is
  193. a 2D design matrix and axis is 1, this would be the number of
  194. columns.
  195. axis: (optional) The axis to normalize. Typically the feature axis.
  196. Defaults to 1.
  197. epsilon: (optional) A small value used for numerical stability in
  198. calculation. Defaults to 1e-4.
  199. initial_scale: (optional) The initial value for the learned scale
  200. parameter. Defaults to 1.0
  201. initial_bias: (optional) The initial value for the learned bias
  202. parameter of the layerwise standard deviation. Defaults to 0.0.
  203. Returns:
  204. A 3-tuple consisting of:
  205. - The layer normalized input blob.
  206. - The mean of the input blob across the given axis.
  207. - The standard deviation of the input blob acress the given axis.
  208. '''
  209. # The learned multiplicative scale or "gain".
  210. scale = model.create_param(
  211. param_name='{}_scale'.format(blob_out),
  212. shape=[dim_in] if isinstance(dim_in, int) else dim_in,
  213. initializer=initializers.Initializer(
  214. 'ConstantFill',
  215. value=initial_scale,
  216. ),
  217. tags=ParameterTags.WEIGHT,
  218. )
  219. # The learned additive bias or "shift".
  220. bias = model.create_param(
  221. param_name='{}_bias'.format(blob_out),
  222. shape=[dim_in] if isinstance(dim_in, int) else dim_in,
  223. initializer=initializers.Initializer(
  224. 'ConstantFill',
  225. value=initial_bias,
  226. ),
  227. tags=ParameterTags.BIAS,
  228. )
  229. normalized, mean, std = model.net.LayerNorm(
  230. [blob_in, scale, bias],
  231. [blob_out, blob_out + "_mean", blob_out + "_std"],
  232. axis=axis,
  233. epsilon=epsilon,
  234. elementwise_affine=True,
  235. )
  236. return normalized, mean, std
  237. def moments_with_running_stats(model, blob_in, blob_out, dim_in,
  238. RunningMeanInitializer=None, RunningVarianceInitializer=None,
  239. order="NCHW", **kwargs):
  240. if model.init_params:
  241. rm_init = ("ConstantFill", {'value': 0.0})
  242. riv_init = ("ConstantFill", {'value': 1.0})
  243. RunningMeanInitializer = initializers.update_initializer(
  244. RunningMeanInitializer, rm_init, ("ConstantFill", {})
  245. )
  246. RunningVarianceInitializer = initializers.update_initializer(
  247. RunningVarianceInitializer, riv_init, ("ConstantFill", {})
  248. )
  249. else:
  250. RunningMeanInitializer = initializers.ExternalInitializer()
  251. RunningVarianceInitializer = initializers.ExternalInitializer()
  252. running_mean = model.create_param(
  253. param_name=blob_out + '_rm',
  254. shape=[dim_in],
  255. initializer=RunningMeanInitializer,
  256. tags=ParameterTags.COMPUTED_PARAM
  257. )
  258. # this is just running variance
  259. running_inv_var = model.create_param(
  260. param_name=blob_out + '_riv',
  261. shape=[dim_in],
  262. initializer=RunningVarianceInitializer,
  263. tags=ParameterTags.COMPUTED_PARAM
  264. )
  265. blob_outs = [blob_out + "_sm", blob_out + "_sv"]
  266. if order == 'NCHW':
  267. blob_outputs = model.net.Moments(
  268. [blob_in], blob_outs,
  269. axes=[0, 2, 3],
  270. order=order, keepdims=False, **kwargs)
  271. elif order == 'NHWC':
  272. blob_outputs = model.net.Moments(
  273. [blob_in], blob_outs,
  274. axes=[0, 1, 2],
  275. order=order, keepdims=False, **kwargs)
  276. return blob_outputs