Caffe2 - Python API
A deep learning, cross platform ML framework
adaptive_weight.py
1 # @package adaptive_weight
2 # Module caffe2.fb.python.layers.adaptive_weight
3 from __future__ import absolute_import, division, print_function, unicode_literals
4 
5 import numpy as np
6 from caffe2.python import core, schema
7 from caffe2.python.layers.layers import ModelLayer
8 from caffe2.python.regularizer import BoundedGradientProjection, LogBarrier
9 
10 
11 """
12 Implementation of adaptive weighting: https://arxiv.org/pdf/1705.07115.pdf
13 """
14 
15 
17  def __init__(
18  self,
19  model,
20  input_record,
21  name="adaptive_weight",
22  optimizer=None,
23  weights=None,
24  enable_diagnose=False,
25  estimation_method="log_std",
26  pos_optim_method="log_barrier",
27  reg_lambda=0.1,
28  **kwargs
29  ):
30  super(AdaptiveWeight, self).__init__(model, name, input_record, **kwargs)
32  np.float32, self.get_next_blob_reference("adaptive_weight")
33  )
34  self.data = self.input_record.field_blobs()
35  self.num = len(self.data)
36  self.optimizer = optimizer
37  if weights is not None:
38  assert len(weights) == self.num
39  else:
40  weights = [1. / self.num for _ in range(self.num)]
41  assert min(weights) > 0, "initial weights must be positive"
42  self.weights = np.array(weights).astype(np.float32)
43  self.estimation_method = str(estimation_method).lower()
44  # used in positivity-constrained parameterization as when the estimation method
45  # is inv_var, with optimization method being either log barrier, or grad proj
46  self.pos_optim_method = str(pos_optim_method).lower()
47  self.reg_lambda = float(reg_lambda)
48  self.enable_diagnose = enable_diagnose
49  self.init_func = getattr(self, self.estimation_method + "_init")
50  self.weight_func = getattr(self, self.estimation_method + "_weight")
51  self.reg_func = getattr(self, self.estimation_method + "_reg")
52  self.init_func()
53  if self.enable_diagnose:
54  self.weight_i = [
55  self.get_next_blob_reference("adaptive_weight_%d" % i)
56  for i in range(self.num)
57  ]
58  for i in range(self.num):
59  self.model.add_ad_hoc_plot_blob(self.weight_i[i])
60 
61  def concat_data(self, net):
62  reshaped = [net.NextScopedBlob("reshaped_data_%d" % i) for i in range(self.num)]
63  # coerce shape for single real values
64  for i in range(self.num):
65  net.Reshape(
66  [self.data[i]],
67  [reshaped[i], net.NextScopedBlob("new_shape_%d" % i)],
68  shape=[1],
69  )
70  concated = net.NextScopedBlob("concated_data")
71  net.Concat(
72  reshaped, [concated, net.NextScopedBlob("concated_new_shape")], axis=0
73  )
74  return concated
75 
76  def log_std_init(self):
77  """
78  mu = 2 log sigma, sigma = standard variance
79  per task objective:
80  min 1 / 2 / e^mu X + mu / 2
81  """
82  values = np.log(1. / 2. / self.weights)
83  initializer = (
84  "GivenTensorFill",
85  {"values": values, "dtype": core.DataType.FLOAT},
86  )
87  self.mu = self.create_param(
88  param_name="mu",
89  shape=[self.num],
90  initializer=initializer,
91  optimizer=self.optimizer,
92  )
93 
94  def log_std_weight(self, x, net, weight):
95  """
96  min 1 / 2 / e^mu X + mu / 2
97  """
98  mu_neg = net.NextScopedBlob("mu_neg")
99  net.Negative(self.mu, mu_neg)
100  mu_neg_exp = net.NextScopedBlob("mu_neg_exp")
101  net.Exp(mu_neg, mu_neg_exp)
102  net.Scale(mu_neg_exp, weight, scale=0.5)
103 
104  def log_std_reg(self, net, reg):
105  net.Scale(self.mu, reg, scale=0.5)
106 
107  def inv_var_init(self):
108  """
109  k = 1 / variance
110  per task objective:
111  min 1 / 2 * k X - 1 / 2 * log k
112  """
113  values = 2. * self.weights
114  initializer = (
115  "GivenTensorFill",
116  {"values": values, "dtype": core.DataType.FLOAT},
117  )
118  if self.pos_optim_method == "log_barrier":
119  regularizer = LogBarrier(reg_lambda=self.reg_lambda)
120  elif self.pos_optim_method == "pos_grad_proj":
121  regularizer = BoundedGradientProjection(lb=0, left_open=True)
122  else:
123  raise TypeError(
124  "unknown positivity optimization method: {}".format(
125  self.pos_optim_method
126  )
127  )
128  self.k = self.create_param(
129  param_name="k",
130  shape=[self.num],
131  initializer=initializer,
132  optimizer=self.optimizer,
133  regularizer=regularizer,
134  )
135 
136  def inv_var_weight(self, x, net, weight):
137  net.Scale(self.k, weight, scale=0.5)
138 
139  def inv_var_reg(self, net, reg):
140  log_k = net.NextScopedBlob("log_k")
141  net.Log(self.k, log_k)
142  net.Scale(log_k, reg, scale=-0.5)
143 
144  def _add_ops_impl(self, net, enable_diagnose):
145  x = self.concat_data(net)
146  weight = net.NextScopedBlob("weight")
147  reg = net.NextScopedBlob("reg")
148  weighted_x = net.NextScopedBlob("weighted_x")
149  weighted_x_add_reg = net.NextScopedBlob("weighted_x_add_reg")
150  self.weight_func(x, net, weight)
151  self.reg_func(net, reg)
152  net.Mul([weight, x], weighted_x)
153  net.Add([weighted_x, reg], weighted_x_add_reg)
154  net.SumElements(weighted_x_add_reg, self.output_schema())
155  if enable_diagnose:
156  for i in range(self.num):
157  net.Slice(weight, self.weight_i[i], starts=[i], ends=[i + 1])
158 
159  def add_ops(self, net):
160  self._add_ops_impl(net, self.enable_diagnose)
def get_next_blob_reference(self, name)
Definition: layers.py:349
def create_param(self, param_name, shape, initializer, optimizer, ps_param=None, regularizer=None)
Definition: layers.py:334