dnn_mod.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. # Copyright (C) 2024 Intel Labs
  2. #
  3. # BSD-3-Clause License
  4. #
  5. # Redistribution and use in source and binary forms, with or without modification,
  6. # are permitted provided that the following conditions are met:
  7. # 1. Redistributions of source code must retain the above copyright notice,
  8. # this list of conditions and the following disclaimer.
  9. # 2. Redistributions in binary form must reproduce the above copyright notice,
  10. # this list of conditions and the following disclaimer in the documentation
  11. # and/or other materials provided with the distribution.
  12. # 3. Neither the name of the copyright holder nor the names of its contributors
  13. # may be used to endorse or promote products derived from this software
  14. # without specific prior written permission.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  18. # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
  20. # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  21. # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  22. # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  23. # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  24. # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  25. # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  26. # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #
  28. # Functions related to DNN to BNN model conversion.
  29. #
  30. # @authors: Mahesh Subedar
  31. #
  32. # ===============================================================================================
  33. from __future__ import absolute_import, division, print_function
  34. import bayesian_torch.layers as bayesian_layers
  35. from bayesian_torch.utils.util import get_rho
  36. # Canonical prior/posterior parameters for the DNN->BNN conversion. Training and
  37. # model loading MUST use the same values so a saved Bayesian state_dict maps onto
  38. # an identically-structured converted model.
  39. DEFAULT_BNN_PRIOR_PARAMETERS = {
  40. "prior_mu": 0.0,
  41. "prior_sigma": 1.0,
  42. "posterior_mu_init": 0.0,
  43. "posterior_rho_init": -3.0,
  44. "type": "Reparameterization",
  45. "moped_enable": False,
  46. "moped_delta": 0.5,
  47. }
  48. # --------------------------------------------------------------------------------
  49. # Parameters used to define BNN layyers.
  50. # bnn_prior_parameters = {
  51. # "prior_mu": 0.0,
  52. # "prior_sigma": 1.0,
  53. # "posterior_mu_init": 0.0,
  54. # "posterior_rho_init": -4.0,
  55. # "type": "Reparameterization", # Flipout or Reparameterization
  56. # }
  57. def bnn_linear_layer(params, d):
  58. layer_type = d.__class__.__name__ + params["type"]
  59. layer_fn = getattr(bayesian_layers, layer_type) # Get BNN layer
  60. bnn_layer = layer_fn(
  61. in_features=d.in_features,
  62. out_features=d.out_features,
  63. prior_mean=params["prior_mu"],
  64. prior_variance=params["prior_sigma"],
  65. posterior_mu_init=params["posterior_mu_init"],
  66. posterior_rho_init=params["posterior_rho_init"],
  67. bias=d.bias is not None,
  68. )
  69. # if MOPED is enabled initialize mu and sigma
  70. if params["moped_enable"]:
  71. delta = params["moped_delta"]
  72. bnn_layer.mu_weight.data.copy_(d.weight.data)
  73. bnn_layer.rho_weight.data.copy_(get_rho(d.weight.data, delta))
  74. if bnn_layer.mu_bias is not None:
  75. bnn_layer.mu_bias.data.copy_(d.bias.data)
  76. bnn_layer.rho_bias.data.copy_(get_rho(d.bias.data, delta))
  77. bnn_layer.dnn_to_bnn_flag = True
  78. return bnn_layer
  79. def bnn_conv_layer(params, d):
  80. layer_type = d.__class__.__name__ + params["type"]
  81. layer_fn = getattr(bayesian_layers, layer_type) # Get BNN layer
  82. bnn_layer = layer_fn(
  83. in_channels=d.in_channels,
  84. out_channels=d.out_channels,
  85. kernel_size=d.kernel_size,
  86. stride=d.stride,
  87. padding=d.padding,
  88. dilation=d.dilation,
  89. groups=d.groups,
  90. prior_mean=params["prior_mu"],
  91. prior_variance=params["prior_sigma"],
  92. posterior_mu_init=params["posterior_mu_init"],
  93. posterior_rho_init=params["posterior_rho_init"],
  94. bias=d.bias is not None,
  95. )
  96. # if MOPED is enabled, initialize mu and sigma
  97. if params["moped_enable"]:
  98. delta = params["moped_delta"]
  99. bnn_layer.mu_kernel.data.copy_(d.weight.data)
  100. bnn_layer.rho_kernel.data.copy_(get_rho(d.weight.data, delta))
  101. if bnn_layer.mu_bias is not None:
  102. bnn_layer.mu_bias.data.copy_(d.bias.data)
  103. bnn_layer.rho_bias.data.copy_(get_rho(d.bias.data, delta))
  104. bnn_layer.dnn_to_bnn_flag = True
  105. return bnn_layer
  106. def bnn_lstm_layer(params, d):
  107. layer_type = d.__class__.__name__ + params["type"]
  108. layer_fn = getattr(bayesian_layers, layer_type) # Get BNN layer
  109. bnn_layer = layer_fn(
  110. in_features=d.input_size,
  111. out_features=d.hidden_size,
  112. prior_mean=params["prior_mu"],
  113. prior_variance=params["prior_sigma"],
  114. posterior_mu_init=params["posterior_mu_init"],
  115. posterior_rho_init=params["posterior_rho_init"],
  116. bias=d.bias is not None,
  117. )
  118. # if MOPED is enabled initialize mu and sigma
  119. if params["moped_enable"]:
  120. print("WARNING: MOPED method is not supported for LSTM layers!!!")
  121. bnn_layer.dnn_to_bnn_flag = True
  122. return bnn_layer
  123. # replaces linear and conv layers
  124. # bnn_prior_parameters - check the template at the top.
  125. # MODIFICATION - PREVENT DOUBLE CONVERSION OF DNN TO BNN LAYERS. IF THE LAYER IS ALREADY CONVERTED, SKIP IT.
  126. def dnn_to_bnn_mod(m, bnn_prior_parameters):
  127. for name, value in list(m._modules.items()):
  128. # SKIP LAYERS THAT ARE ALREADY CONVERTED TO BNN LAYERS - ENDS IN "Reparameterization" OR "Flipout"
  129. if m._modules[name].__class__.__name__.endswith(
  130. "Reparameterization"
  131. ) or m._modules[name].__class__.__name__.endswith("Flipout"):
  132. continue
  133. if m._modules[name]._modules:
  134. dnn_to_bnn_mod(m._modules[name], bnn_prior_parameters)
  135. elif "Conv" in m._modules[name].__class__.__name__:
  136. setattr(m, name, bnn_conv_layer(bnn_prior_parameters, m._modules[name]))
  137. elif "Linear" in m._modules[name].__class__.__name__:
  138. setattr(m, name, bnn_linear_layer(bnn_prior_parameters, m._modules[name]))
  139. elif "LSTM" in m._modules[name].__class__.__name__:
  140. setattr(m, name, bnn_lstm_layer(bnn_prior_parameters, m._modules[name]))
  141. else:
  142. pass
  143. return
  144. def get_kl_loss(m):
  145. kl_loss = None
  146. for layer in m.modules():
  147. if hasattr(layer, "kl_loss"):
  148. if kl_loss is None:
  149. kl_loss = layer.kl_loss()
  150. else:
  151. kl_loss += layer.kl_loss()
  152. return kl_loss