A tower function (see `tutorial on tower function `_) It keeps track of the name scope, variable scope and input/output tensors each time the function is called. :class:`TowerTrainer` needs this so
| 249 | |
| 250 | |
| 251 | class TowerFunc(object): |
| 252 | """ |
| 253 | A tower function (see |
| 254 | `tutorial on tower function |
| 255 | <http://tensorpack.readthedocs.io/tutorial/extend/trainer.html#tower-trainer>`_) |
| 256 | It keeps track of the name scope, variable scope and input/output tensors |
| 257 | each time the function is called. |
| 258 | |
| 259 | :class:`TowerTrainer` needs this so that it knows how to build a predictor. |
| 260 | |
| 261 | Conceptually, this class is roughly equivalent to `tf.function` with input signature, introduced in TF 2.0. |
| 262 | """ |
| 263 | |
| 264 | def __init__(self, tower_fn, input_signature): |
| 265 | """ |
| 266 | Args: |
| 267 | tower_func: a function which builds one tower in the graph. |
| 268 | It takes several input tensors and could return anything. |
| 269 | input_signature ([TensorSpec]): list of :class:`tf.TensorSpec`. |
| 270 | They are used to figure out the names for the input tensors. |
| 271 | """ |
| 272 | assert callable(tower_fn), tower_fn |
| 273 | self._inputs_names = [k.name for k in input_signature] |
| 274 | assert len(set(self._inputs_names)) == len(self._inputs_names), \ |
| 275 | "Duplicated names in input_signature! " + str(self._inputs_names) |
| 276 | for name in self._inputs_names: |
| 277 | if any(k in name for k in [':', '/', ' ']): |
| 278 | raise ValueError("Invalid input name: '{}'".format(name)) |
| 279 | self._tower_fn = tower_fn |
| 280 | self._input_signature = input_signature |
| 281 | |
| 282 | self._handles = [] |
| 283 | |
| 284 | def __new__(cls, tower_fn, _): |
| 285 | # to avoid double-wrapping a function |
| 286 | if isinstance(tower_fn, TowerFunc): |
| 287 | return tower_fn |
| 288 | else: |
| 289 | return super(TowerFunc, cls).__new__(cls) |
| 290 | |
| 291 | def __call__(self, *args): |
| 292 | ctx = get_current_tower_context() |
| 293 | assert ctx is not None, "Function must be called under TowerContext!" |
| 294 | output = self._tower_fn(*args) |
| 295 | handle = TowerTensorHandle(ctx, args, output, self._input_signature) |
| 296 | self._handles.append(handle) |
| 297 | return output |
| 298 | |
| 299 | @property |
| 300 | def towers(self): |
| 301 | """ |
| 302 | TowerTensorHandles: a :class:`TowerTensorHandles` object, that can |
| 303 | access the tower handles by either indices or names. |
| 304 | """ |
| 305 | return TowerTensorHandles(self._handles) |
| 306 | |
| 307 | @property |
| 308 | def input_signature(self): |
no outgoing calls
no test coverage detected