conv.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. ## @package conv
  2. # Module caffe2.python.helpers.conv
  3. from caffe2.python import core
  4. from caffe2.python.modeling import initializers
  5. from caffe2.python.modeling.parameter_info import ParameterTags
  6. def _ConvBase(
  7. model,
  8. is_nd,
  9. blob_in,
  10. blob_out,
  11. dim_in,
  12. dim_out,
  13. kernel,
  14. weight_init=None,
  15. bias_init=None,
  16. WeightInitializer=None,
  17. BiasInitializer=None,
  18. group=1,
  19. transform_inputs=None,
  20. use_cudnn=False,
  21. order="NCHW",
  22. cudnn_exhaustive_search=False,
  23. ws_nbytes_limit=None,
  24. float16_compute=False,
  25. **kwargs
  26. ):
  27. kernels = []
  28. if is_nd:
  29. if not isinstance(kernel, list):
  30. kernels = [kernel]
  31. else:
  32. kernels = kernel
  33. else:
  34. if isinstance(kernel, list):
  35. assert len(kernel) == 2, "Conv support only a 2D kernel."
  36. kernels = kernel
  37. else:
  38. kernels = [kernel] * 2
  39. requested_engine = kwargs.get('engine')
  40. if requested_engine is not None:
  41. if use_cudnn and requested_engine != 'CUDNN':
  42. raise ValueError(
  43. 'When use_cudnn=True, the only engine you can specify is '
  44. '"CUDNN"')
  45. elif not use_cudnn and requested_engine == 'CUDNN':
  46. raise ValueError(
  47. 'When use_cudnn=False, the only engine you can specify is '
  48. '""')
  49. if use_cudnn:
  50. kwargs['engine'] = 'CUDNN'
  51. kwargs['exhaustive_search'] = cudnn_exhaustive_search
  52. if ws_nbytes_limit:
  53. kwargs['ws_nbytes_limit'] = ws_nbytes_limit
  54. use_bias =\
  55. False if ("no_bias" in kwargs and kwargs["no_bias"]) else True
  56. blob_out = blob_out or model.net.NextName()
  57. weight_shape = [dim_out]
  58. if order == "NCHW":
  59. weight_shape.append(int(dim_in / group))
  60. weight_shape.extend(kernels)
  61. else:
  62. weight_shape.extend(kernels)
  63. weight_shape.append(int(dim_in / group))
  64. WeightInitializer = initializers.update_initializer(
  65. WeightInitializer, weight_init, ("XavierFill", {})
  66. )
  67. BiasInitializer = initializers.update_initializer(
  68. BiasInitializer, bias_init, ("ConstantFill", {})
  69. )
  70. if not model.init_params:
  71. WeightInitializer = initializers.ExternalInitializer()
  72. BiasInitializer = initializers.ExternalInitializer()
  73. weight = model.create_param(
  74. param_name=blob_out + '_w',
  75. shape=weight_shape,
  76. initializer=WeightInitializer,
  77. tags=ParameterTags.WEIGHT
  78. )
  79. if use_bias:
  80. bias = model.create_param(
  81. param_name=blob_out + '_b',
  82. shape=[dim_out, ],
  83. initializer=BiasInitializer,
  84. tags=ParameterTags.BIAS
  85. )
  86. if use_bias:
  87. inputs = [blob_in, weight, bias]
  88. else:
  89. inputs = [blob_in, weight]
  90. if transform_inputs is not None:
  91. transform_inputs(model, blob_out, inputs)
  92. # Enable float 16 compute kernel (relevant for CUDA)
  93. if float16_compute:
  94. kwargs['float16_compute'] = True
  95. # For the operator, we no longer need to provide the no_bias field
  96. # because it can automatically figure this out from the number of
  97. # inputs.
  98. if 'no_bias' in kwargs:
  99. del kwargs['no_bias']
  100. if group != 1:
  101. kwargs['group'] = group
  102. if is_nd:
  103. return model.net.Conv(
  104. inputs,
  105. blob_out,
  106. kernels=kernels,
  107. order=order,
  108. **kwargs)
  109. else:
  110. if isinstance(kernel, list):
  111. return model.net.Conv(
  112. inputs,
  113. blob_out,
  114. kernel_h=kernel[0],
  115. kernel_w=kernel[1],
  116. order=order,
  117. **kwargs)
  118. else:
  119. return model.net.Conv(
  120. inputs,
  121. blob_out,
  122. kernel=kernel,
  123. order=order,
  124. **kwargs)
  125. def conv_nd(
  126. model,
  127. blob_in,
  128. blob_out,
  129. dim_in,
  130. dim_out,
  131. kernel,
  132. weight_init=None,
  133. bias_init=None,
  134. WeightInitializer=None,
  135. BiasInitializer=None,
  136. group=1,
  137. transform_inputs=None,
  138. order="NCHW",
  139. **kwargs
  140. ):
  141. """N-dimensional convolution for inputs with NCHW storage order.
  142. """
  143. assert order == "NCHW", "ConvNd only supported for NCHW storage."
  144. return _ConvBase(model, True, blob_in, blob_out, dim_in, dim_out, kernel,
  145. weight_init, bias_init, WeightInitializer, BiasInitializer,
  146. group, transform_inputs, order=order, **kwargs)
  147. def conv(
  148. model,
  149. blob_in,
  150. blob_out,
  151. dim_in,
  152. dim_out,
  153. kernel,
  154. weight_init=None,
  155. bias_init=None,
  156. WeightInitializer=None,
  157. BiasInitializer=None,
  158. group=1,
  159. transform_inputs=None,
  160. **kwargs
  161. ):
  162. """2-dimensional convolution.
  163. """
  164. return _ConvBase(model, False, blob_in, blob_out, dim_in, dim_out, kernel,
  165. weight_init, bias_init, WeightInitializer, BiasInitializer,
  166. group, transform_inputs, **kwargs)
  167. def conv_transpose(
  168. model,
  169. blob_in,
  170. blob_out,
  171. dim_in,
  172. dim_out,
  173. kernel,
  174. weight_init=None,
  175. bias_init=None,
  176. use_cudnn=False,
  177. order="NCHW",
  178. cudnn_exhaustive_search=False,
  179. ws_nbytes_limit=None,
  180. **kwargs
  181. ):
  182. """ConvTranspose.
  183. """
  184. weight_init = weight_init if weight_init else ('XavierFill', {})
  185. bias_init = bias_init if bias_init else ('ConstantFill', {})
  186. blob_out = blob_out or model.net.NextName()
  187. weight_shape = (
  188. [dim_in, dim_out, kernel, kernel]
  189. if order == "NCHW" else [dim_in, kernel, kernel, dim_out]
  190. )
  191. if model.init_params:
  192. weight = model.param_init_net.__getattr__(weight_init[0])(
  193. [],
  194. blob_out + '_w',
  195. shape=weight_shape,
  196. **weight_init[1]
  197. )
  198. bias = model.param_init_net.__getattr__(bias_init[0])(
  199. [],
  200. blob_out + '_b',
  201. shape=[dim_out, ],
  202. **bias_init[1]
  203. )
  204. else:
  205. weight = core.ScopedBlobReference(
  206. blob_out + '_w', model.param_init_net)
  207. bias = core.ScopedBlobReference(
  208. blob_out + '_b', model.param_init_net)
  209. model.AddParameter(weight, ParameterTags.WEIGHT)
  210. model.AddParameter(bias, ParameterTags.BIAS)
  211. if use_cudnn:
  212. kwargs['engine'] = 'CUDNN'
  213. kwargs['exhaustive_search'] = cudnn_exhaustive_search
  214. if ws_nbytes_limit:
  215. kwargs['ws_nbytes_limit'] = ws_nbytes_limit
  216. return model.net.ConvTranspose(
  217. [blob_in, weight, bias],
  218. blob_out,
  219. kernel=kernel,
  220. order=order,
  221. **kwargs
  222. )
  223. def group_conv(
  224. model,
  225. blob_in,
  226. blob_out,
  227. dim_in,
  228. dim_out,
  229. kernel,
  230. weight_init=None,
  231. bias_init=None,
  232. group=1,
  233. **kwargs
  234. ):
  235. """Group Convolution.
  236. This is essentially the same as Conv with a group argument passed in.
  237. We specialize this for backward interface compatibility.
  238. """
  239. return conv(model, blob_in, blob_out, dim_in, dim_out, kernel,
  240. weight_init=weight_init, bias_init=bias_init,
  241. group=group, **kwargs)
  242. def group_conv_deprecated(
  243. model,
  244. blob_in,
  245. blob_out,
  246. dim_in,
  247. dim_out,
  248. kernel,
  249. weight_init=None,
  250. bias_init=None,
  251. group=1,
  252. use_cudnn=False,
  253. order="NCHW",
  254. cudnn_exhaustive_search=False,
  255. ws_nbytes_limit=None,
  256. **kwargs
  257. ):
  258. """GroupConvolution's deprecated interface.
  259. This is used to simulate a group convolution via split and concat. You
  260. should always use the new group convolution in your new code.
  261. """
  262. weight_init = weight_init if weight_init else ('XavierFill', {})
  263. bias_init = bias_init if bias_init else ('ConstantFill', {})
  264. use_bias = False if ("no_bias" in kwargs and kwargs["no_bias"]) else True
  265. if use_cudnn:
  266. kwargs['engine'] = 'CUDNN'
  267. kwargs['exhaustive_search'] = cudnn_exhaustive_search
  268. if ws_nbytes_limit:
  269. kwargs['ws_nbytes_limit'] = ws_nbytes_limit
  270. if dim_in % group:
  271. raise ValueError("dim_in should be divisible by group.")
  272. if dim_out % group:
  273. raise ValueError("dim_out should be divisible by group.")
  274. splitted_blobs = model.net.DepthSplit(
  275. blob_in,
  276. ['_' + blob_out + '_gconv_split_' + str(i) for i in range(group)],
  277. dimensions=[int(dim_in / group) for i in range(group)],
  278. order=order
  279. )
  280. weight_shape = (
  281. [dim_out / group, dim_in / group, kernel, kernel]
  282. if order == "NCHW" else
  283. [dim_out / group, kernel, kernel, dim_in / group]
  284. )
  285. # Make sure that the shapes are of int format. Especially for py3 where
  286. # int division gives float output.
  287. weight_shape = [int(v) for v in weight_shape]
  288. conv_blobs = []
  289. for i in range(group):
  290. if model.init_params:
  291. weight = model.param_init_net.__getattr__(weight_init[0])(
  292. [],
  293. blob_out + '_gconv_%d_w' % i,
  294. shape=weight_shape,
  295. **weight_init[1]
  296. )
  297. if use_bias:
  298. bias = model.param_init_net.__getattr__(bias_init[0])(
  299. [],
  300. blob_out + '_gconv_%d_b' % i,
  301. shape=[int(dim_out / group)],
  302. **bias_init[1]
  303. )
  304. else:
  305. weight = core.ScopedBlobReference(
  306. blob_out + '_gconv_%d_w' % i, model.param_init_net)
  307. if use_bias:
  308. bias = core.ScopedBlobReference(
  309. blob_out + '_gconv_%d_b' % i, model.param_init_net)
  310. model.AddParameter(weight, ParameterTags.WEIGHT)
  311. if use_bias:
  312. model.AddParameter(bias, ParameterTags.BIAS)
  313. if use_bias:
  314. inputs = [weight, bias]
  315. else:
  316. inputs = [weight]
  317. if 'no_bias' in kwargs:
  318. del kwargs['no_bias']
  319. conv_blobs.append(
  320. splitted_blobs[i].Conv(
  321. inputs,
  322. blob_out + '_gconv_%d' % i,
  323. kernel=kernel,
  324. order=order,
  325. **kwargs
  326. )
  327. )
  328. concat, concat_dims = model.net.Concat(
  329. conv_blobs,
  330. [blob_out,
  331. "_" + blob_out + "_concat_dims"],
  332. order=order
  333. )
  334. return concat