Skip to content

Commit 5e7a03b

Browse files
fixed all jacobians and hessian modes, depreceated hessian by obs
kept batched_obs analytic hessian, the single observation one was just slower.
1 parent 886a241 commit 5e7a03b

File tree

4 files changed

+49
-71
lines changed

4 files changed

+49
-71
lines changed

batchglm/train/tf/nb_glm/estimator.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,9 @@ def map_model(idx, data) -> BasicModelGraph:
7575
with tf.name_scope("loss"):
7676
loss = tf.reduce_sum(norm_neg_log_likelihood)
7777

78-
# TODO: remove this and decide for one implementation
79-
if pkg_constants.HESSIAN_MODE == "obs":
80-
# Only need iterator that yields single observations for hessian mode obs:
81-
singleobs_data = dataset.map(fetch_fn, num_parallel_calls=pkg_constants.TF_NUM_THREADS)
82-
singleobs_data = singleobs_data.prefetch(1)
83-
else:
84-
singleobs_data = None
85-
8678
with tf.name_scope("hessians"):
8779
hessians = Hessians(
8880
batched_data=batched_data,
89-
singleobs_data=singleobs_data,
9081
sample_indices=sample_indices,
9182
constraints_loc=constraints_loc,
9283
constraints_scale=constraints_scale,
@@ -268,7 +259,6 @@ def __init__(
268259
# Define the hessian on the batched model for newton-rhapson:
269260
batch_hessians = Hessians(
270261
batched_data=batch_data,
271-
singleobs_data=None,
272262
sample_indices=batch_sample_index,
273263
constraints_loc=constraints_loc,
274264
constraints_scale=constraints_scale,

batchglm/train/tf/nb_glm/hessians.py

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ class Hessians:
175175
def __init__(
176176
self,
177177
batched_data: tf.data.Dataset,
178-
singleobs_data: tf.data.Dataset,
179178
sample_indices: tf.Tensor,
180179
constraints_loc,
181180
constraints_scale,
@@ -188,7 +187,6 @@ def __init__(
188187
189188
:param batched_data:
190189
Dataset iterator over mini-batches of data (used for training) or tf.Tensors of mini-batch.
191-
:param singleobs_data: Dataset iterator over single observation batches of data.
192190
:param sample_indices: Indices of samples to be used.
193191
:param constraints_loc: Constraints for location model.
194192
Array with constraints in rows and model parameters in columns.
@@ -218,29 +216,14 @@ def __init__(
218216
evaluation of the hessian via the tf.hessian function,
219217
which is done by feature for implementation reasons.
220218
:param iterator: bool
221-
Whether an iterator or a tensor (single yield of an iterator) is given
222-
in
219+
Whether batched_data is an iterator or a tensor (such as single yield of an iterator).
223220
"""
224221
if constraints_loc is not None and mode != "tf":
225222
raise ValueError("closed form hessian does not work if constraints_loc is not None")
226223
if constraints_scale is not None and mode != "tf":
227224
raise ValueError("closed form hessian does not work if constraints_scale is not None")
228225

229-
if mode == "obs":
230-
logger.info("Performance warning for hessian mode: " +
231-
"obs_batched is strongly recommended as an alternative to obs.")
232-
self.hessian = self.byobs(
233-
batched_data=singleobs_data,
234-
sample_indices=sample_indices,
235-
constraints_loc=constraints_loc,
236-
constraints_scale=constraints_scale,
237-
model_vars=model_vars,
238-
batched=False,
239-
iterator=iterator,
240-
dtype=dtype
241-
)
242-
self.neg_hessian = tf.negative(self.hessian)
243-
elif mode == "obs_batched":
226+
if mode == "obs_batched":
244227
self.hessian = self.byobs(
245228
batched_data=batched_data,
246229
sample_indices=sample_indices,
@@ -259,6 +242,7 @@ def __init__(
259242
constraints_loc=constraints_loc,
260243
constraints_scale=constraints_scale,
261244
model_vars=model_vars,
245+
iterator=iterator,
262246
dtype=dtype
263247
)
264248
self.neg_hessian = tf.negative(self.hessian)
@@ -272,6 +256,7 @@ def __init__(
272256
constraints_loc=constraints_loc,
273257
constraints_scale=constraints_scale,
274258
model_vars=model_vars,
259+
iterator=iterator,
275260
dtype=dtype
276261
)
277262
self.hessian = tf.negative(self.neg_hessian)
@@ -542,6 +527,7 @@ def byfeature(
542527
constraints_loc,
543528
constraints_scale,
544529
model_vars: ModelVars,
530+
iterator,
545531
dtype
546532
):
547533
"""
@@ -688,15 +674,21 @@ def _red(prev, cur):
688674
p_shape_a = model_vars.a.shape[0]
689675
p_shape_b = model_vars.b.shape[0]
690676

691-
H = op_utils.map_reduce(
692-
last_elem=tf.gather(sample_indices, tf.size(sample_indices) - 1),
693-
data=batched_data,
694-
map_fn=_map,
695-
reduce_fn=_red,
696-
parallel_iterations=1,
697-
)
698-
H = H[0]
699-
return H
677+
if iterator:
678+
H = op_utils.map_reduce(
679+
last_elem=tf.gather(sample_indices, tf.size(sample_indices) - 1),
680+
data=batched_data,
681+
map_fn=_map,
682+
reduce_fn=_red,
683+
parallel_iterations=1
684+
)
685+
else:
686+
H = _map(
687+
idx=sample_indices,
688+
data=batched_data
689+
)
690+
691+
return H[0]
700692

701693
def tf_byfeature(
702694
self,
@@ -705,6 +697,7 @@ def tf_byfeature(
705697
constraints_loc,
706698
constraints_scale,
707699
model_vars: ModelVars,
700+
iterator,
708701
dtype
709702
) -> List[tf.Tensor]:
710703
"""
@@ -813,11 +806,18 @@ def _map(idx, data):
813806
def _red(prev, cur):
814807
return [tf.add(p, c) for p, c in zip(prev, cur)]
815808

816-
H = op_utils.map_reduce(
817-
last_elem=tf.gather(sample_indices, tf.size(sample_indices) - 1),
818-
data=batched_data,
819-
map_fn=_map,
820-
reduce_fn=_red,
821-
parallel_iterations=1,
822-
)
809+
if iterator:
810+
H = op_utils.map_reduce(
811+
last_elem=tf.gather(sample_indices, tf.size(sample_indices) - 1),
812+
data=batched_data,
813+
map_fn=_map,
814+
reduce_fn=_red,
815+
parallel_iterations=1
816+
)
817+
else:
818+
H = _map(
819+
idx=sample_indices,
820+
data=batched_data
821+
)
822+
823823
return H[0]

batchglm/unit_test/test_nb_glm_hessians.py

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,16 @@ def test_compute_hessians(self):
5353
design_scale = data_utils.design_matrix(sample_description, formula="~ 1 + condition")
5454

5555
input_data = InputData.new(sim.X, design_loc=design_loc, design_scale=design_scale)
56-
print(input_data)
56+
57+
pkg_constants.HESSIAN_MODE = "tf"
58+
self.estimator_tf = estimate(input_data)
59+
t0_tf = time.time()
60+
# tensorflow computes the negative hessian as the
61+
# objective is the negative log-likelihood.
62+
self.H_tf = self.estimator_tf.hessians
63+
t1_tf = time.time()
64+
self.estimator_tf.close_session()
65+
self.t_tf = t1_tf - t0_tf
5766

5867
pkg_constants.HESSIAN_MODE = "obs_batched"
5968
self.estimator_ob = estimate(input_data)
@@ -63,14 +72,6 @@ def test_compute_hessians(self):
6372
self.estimator_ob.close_session()
6473
self.t_ob = t1_ob - t0_ob
6574

66-
pkg_constants.HESSIAN_MODE = "obs"
67-
self.estimator_ow = estimate(input_data)
68-
t0_ow = time.time()
69-
self.H_ow = self.estimator_ow.hessians
70-
t1_ow = time.time()
71-
self.estimator_ow.close_session()
72-
self.t_ow = t1_ow - t0_ow
73-
7475
pkg_constants.HESSIAN_MODE = "feature"
7576
self.estimator_fw = estimate(input_data)
7677
t0_fw = time.time()
@@ -79,28 +80,15 @@ def test_compute_hessians(self):
7980
self.estimator_fw.close_session()
8081
self.t_fw = t1_fw - t0_fw
8182

82-
pkg_constants.HESSIAN_MODE = "tf"
83-
self.estimator_tf = estimate(input_data)
84-
t0_tf = time.time()
85-
# tensorflow computes the negative hessian as the
86-
# objective is the negative log-likelihood.
87-
self.H_tf = -self.estimator_tf.hessians
88-
t1_tf = time.time()
89-
self.estimator_tf.close_session()
90-
self.t_tf = t1_tf - t0_tf
91-
9283
i = 1
9384
print("\n")
94-
print("run time observation-wise analytic solution: ", str(self.t_ow))
9585
print("run time observation batch-wise analytic solution: ", str(self.t_ob))
9686
print("run time feature-wise analytic solution: ", str(self.t_fw))
9787
print("run time feature-wise tensorflow solution: ", str(self.t_tf))
98-
print("ratio of analytic feature-wise hessian to analytic observation-wise hessian:")
99-
print(self.H_tf.values[i, :, :] / self.H_ow.values[i, :, :])
100-
print("ratio of analytic feature-wise hessian to analytic observation batch-wise hessian:")
88+
print("ratio of tensorflow feature-wise hessian to analytic observation batch-wise hessian:")
10189
print(self.H_tf.values[i, :, :] / self.H_ob.values[i, :, :])
102-
print("ratio of tensorflow feature-wise hessian to analytic observation-wise hessian:")
103-
print(self.H_tf.values[i, :, :] / self.H_ow.values[i, :, :])
90+
print("ratio of tensorflow feature-wise hessian to analytic feature-wise hessian:")
91+
print(self.H_tf.values[i, :, :] / self.H_fw.values[i, :, :])
10492

10593

10694
if __name__ == '__main__':

batchglm/unit_test/test_nb_glm_jacobians.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def setUp(self):
3535
def tearDown(self):
3636
pass
3737

38-
def test_compute_hessians(self):
38+
def test_compute_jacobians(self):
3939
logging.getLogger("tensorflow").setLevel(logging.ERROR)
4040
logging.getLogger("batchglm").setLevel(logging.INFO)
4141

0 commit comments

Comments
 (0)