Skip to content

Commit 8e77d45

Browse files
committed
Add automatic type casting of input data to nb_glm estimator
1 parent ad81c5a commit 8e77d45

4 files changed

Lines changed: 102 additions & 77 deletions

File tree

batchglm/models/nb/base.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def param_shapes(cls) -> dict:
4747
return INPUT_DATA_PARAMS
4848

4949
@classmethod
50-
def new(cls, data, observation_names=None, feature_names=None, dtype="float32"):
50+
def new(cls, data, observation_names=None, feature_names=None, cast_dtype=None):
5151
"""
5252
Create a new InputData object.
5353
@@ -62,12 +62,14 @@ def new(cls, data, observation_names=None, feature_names=None, dtype="float32"):
6262
stored as data[design_loc] and data[design_scale]
6363
:param observation_names: (optional) names of the observations.
6464
:param feature_names: (optional) names of the features.
65-
:param dtype: data type of all data; should be either float32 or float64
65+
:param cast_dtype: data type of all data; should be either float32 or float64
6666
:return: InputData object
6767
"""
6868
X = data_utils.xarray_from_data(data)
69-
X = X.astype(dtype)
70-
# X = X.chunk({"observations": 1})
69+
70+
if cast_dtype is not None:
71+
X = X.astype(cast_dtype)
72+
# X = X.chunk({"observations": 1})
7173

7274
retval = cls(xr.Dataset({
7375
"X": X,

batchglm/models/nb_glm/base.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ def new(
8787
feature_names=None,
8888
design_loc_key="design_loc",
8989
design_scale_key="design_scale",
90-
dtype="float32"
90+
cast_dtype=None
9191
):
9292
"""
9393
Create a new InputData object.
@@ -116,22 +116,23 @@ def new(
116116
:param feature_names: (optional) names of the features.
117117
:param design_loc_key: Where to find `design_loc` if `data` is some anndata.AnnData or xarray.Dataset.
118118
:param design_scale_key: Where to find `design_scale` if `data` is some anndata.AnnData or xarray.Dataset.
119-
:param dtype: data type of all data; should be either float32 or float64
119+
:param cast_dtype: If this option is set, all provided data will be casted to this data type.
120120
:return: InputData object
121121
"""
122122
retval = super(InputData, cls).new(
123123
data=data,
124124
observation_names=observation_names,
125125
feature_names=feature_names,
126-
dtype=dtype
126+
cast_dtype=cast_dtype
127127
)
128128

129129
design_loc = _parse_design(data, design_loc, design_loc_names, design_loc_key, "design_loc_params")
130130
design_scale = _parse_design(data, design_scale, design_scale_names, design_scale_key, "design_scale_params")
131131

132-
design_loc = design_loc.astype(dtype)
133-
design_scale = design_scale.astype(dtype)
134-
# design = design.chunk({"observations": 1})
132+
if cast_dtype is not None:
133+
design_loc = design_loc.astype(cast_dtype)
134+
design_scale = design_scale.astype(cast_dtype)
135+
# design = design.chunk({"observations": 1})
135136

136137
retval.design_loc = design_loc
137138
retval.design_scale = design_scale

batchglm/train/tf/nb_glm/estimator.py

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ def __init__(
310310
dataset = tf.data.Dataset.from_tensor_slices(sample_indices)
311311

312312
batched_data = dataset.batch(batch_size)
313-
batched_data = batched_data.map(fetch_fn)
313+
batched_data = batched_data.map(fetch_fn, num_parallel_calls=pkg_constants.TF_NUM_THREADS)
314314
batched_data = batched_data.prefetch(1)
315315

316316
def map_model(idx, data) -> BasicModelGraph:
@@ -434,7 +434,7 @@ def __init__(
434434
training_data = data_indices.apply(tf.contrib.data.shuffle_and_repeat(buffer_size=2 * batch_size))
435435
# training_data = training_data.apply(tf.contrib.data.batch_and_drop_remainder(batch_size))
436436
training_data = training_data.batch(batch_size, drop_remainder=True)
437-
training_data = training_data.map(fetch_fn)
437+
training_data = training_data.map(fetch_fn, num_parallel_calls=pkg_constants.TF_NUM_THREADS)
438438
training_data = training_data.prefetch(buffer_size)
439439

440440
iterator = training_data.make_one_shot_iterator()
@@ -768,7 +768,7 @@ class TrainingStrategy(Enum):
768768
"stop_at_loss_change": 0.05,
769769
"loss_window_size": 10,
770770
"use_batching": False,
771-
"optim_algo": "GD",
771+
"optim_algo": "ADAM",
772772
},
773773
]
774774
EXACT = [
@@ -814,7 +814,7 @@ class TrainingStrategy(Enum):
814814
"stop_at_loss_change": 0.25,
815815
"loss_window_size": 10,
816816
"use_batching": False,
817-
"optim_algo": "GD",
817+
"optim_algo": "ADAM",
818818
},
819819
]
820820

@@ -837,6 +837,7 @@ def __init__(
837837
quick_scale=False,
838838
model: EstimatorGraph = None,
839839
extended_summary=False,
840+
dtype="float64",
840841
):
841842
"""
842843
Create a new Estimator
@@ -871,8 +872,6 @@ def __init__(
871872
:param extended_summary: Include detailed information in the summaries.
872873
Will drastically increase runtime of summary writer, use only for debugging.
873874
"""
874-
dtype = input_data.X.dtype
875-
876875
# validate design matrix:
877876
if np.linalg.matrix_rank(input_data.design_loc) != np.linalg.matrix_rank(input_data.design_loc.T):
878877
raise ValueError("design_loc matrix is not full rank")
@@ -920,9 +919,9 @@ def __init__(
920919

921920
logger.info("Using closed-form MLE initialization for mean")
922921
logger.debug("RMSE of closed-form mean:\n%s", a_prime[1])
923-
logger.debug("Should train mu:\t%s", self._train_mu)
922+
logger.info("Should train mu: %s", self._train_mu)
924923
except np.linalg.LinAlgError:
925-
pass
924+
logger.warning("Closed form initialization failed!")
926925

927926
if isinstance(init_b, str) and (init_b.lower() == "auto" or init_b.lower() == "closed_form"):
928927
try:
@@ -951,9 +950,9 @@ def __init__(
951950

952951
logger.info("Using closed-form MME initialization for dispersion")
953952
logger.debug("RMSE of closed-form dispersion:\n%s", b_prime[1])
954-
logger.debug("Should train r:\t%s", self._train_r)
953+
logger.info("Should train r: %s", self._train_r)
955954
except np.linalg.LinAlgError:
956-
pass
955+
logger.warning("Closed form initialization failed!")
957956

958957
if init_model is not None:
959958
if isinstance(init_a, str) and (init_a.lower() == "auto" or init_a.lower() == "init_model"):
@@ -992,33 +991,56 @@ def __init__(
992991

993992
# ### prepare fetch_fn:
994993
def fetch_fn(idx):
995-
X_tensor = tf.py_func(input_data.fetch_X, [idx], dtype)
996-
X_tensor.set_shape(
997-
idx.get_shape().as_list() + [input_data.num_features]
994+
X_tensor = tf.py_func(
995+
func=input_data.fetch_X,
996+
inp=[idx],
997+
Tout=input_data.X.dtype,
998+
stateful=False
998999
)
999-
1000-
design_loc_tensor = tf.py_func(input_data.fetch_design_loc, [idx], dtype)
1001-
design_loc_tensor.set_shape(
1002-
idx.get_shape().as_list() + [input_data.num_design_loc_params]
1000+
X_tensor.set_shape(idx.get_shape().as_list() + [input_data.num_features])
1001+
X_tensor = tf.cast(X_tensor, dtype=dtype)
1002+
1003+
design_loc_tensor = tf.py_func(
1004+
func=input_data.fetch_design_loc,
1005+
inp=[idx],
1006+
Tout=input_data.design_loc.dtype,
1007+
stateful=False
10031008
)
1004-
design_scale_tensor = tf.py_func(input_data.fetch_design_scale, [idx], dtype)
1005-
design_scale_tensor.set_shape(
1006-
idx.get_shape().as_list() + [input_data.num_design_scale_params]
1009+
design_loc_tensor.set_shape(idx.get_shape().as_list() + [input_data.num_design_loc_params])
1010+
design_loc_tensor = tf.cast(design_loc_tensor, dtype=dtype)
1011+
1012+
design_scale_tensor = tf.py_func(
1013+
func=input_data.fetch_design_scale,
1014+
inp=[idx],
1015+
Tout=input_data.design_scale.dtype,
1016+
stateful=False
10071017
)
1018+
design_scale_tensor.set_shape(idx.get_shape().as_list() + [input_data.num_design_scale_params])
1019+
design_scale_tensor = tf.cast(design_scale_tensor, dtype=dtype)
10081020

10091021
if input_data.size_factors is not None:
1010-
size_factors_tensor = tf.log(tf.py_func(input_data.fetch_size_factors, [idx], dtype))
1022+
size_factors_tensor = tf.log(tf.py_func(
1023+
func=input_data.fetch_size_factors,
1024+
inp=[idx],
1025+
Tout=input_data.size_factors.dtype,
1026+
stateful=False
1027+
))
10111028
size_factors_tensor.set_shape(idx.get_shape())
1029+
size_factors_tensor = tf.cast(size_factors_tensor, dtype=dtype)
10121030
else:
1013-
size_factors_tensor = tf.constant(0, shape=(), dtype=X_tensor.dtype)
1031+
size_factors_tensor = tf.constant(0, shape=(), dtype=dtype)
10141032

10151033
# return idx, data
10161034
return idx, (X_tensor, design_loc_tensor, design_scale_tensor, size_factors_tensor)
10171035

10181036
if isinstance(init_a, str):
10191037
init_a = None
1038+
else:
1039+
init_a = init_a.astype(dtype)
10201040
if isinstance(init_b, str):
10211041
init_b = None
1042+
else:
1043+
init_b = init_b.astype(dtype)
10221044

10231045
with graph.as_default():
10241046
# create model

0 commit comments

Comments
 (0)