TensorDictBase.apply#
- TensorDictBase.apply(fn: Callable, *others: T, batch_size: Sequence[int] | None = None, device: device | None = NO_DEFAULT, names: Sequence[str] | None = NO_DEFAULT, inplace: bool = False, default: Any = NO_DEFAULT, filter_empty: bool | None = None, propagate_lock: bool = False, call_on_nested: bool = False, is_leaf: Callable[[type], bool] | None = None, out: TensorDictBase | None = None, **constructor_kwargs) Self | None#
Applies a callable to every leaf and returns a new tensordict with the results.
fnis called on each tensor leaf, in the nested tensordicts too, and its result is stored under the same key. IffnreturnsNone, the entry is left out of the result, which can be used to filter entries. Withothers,fnreceives the leaf of each tensordict under the same key. For a callable that also receives the key, seenamed_apply().- Parameters:
fn (Callable) – the function called on each leaf, as
fn(leaf, *other_leaves). It returns a tensor, a tensordict, orNoneto leave the entry out.*others (TensorDictBase) – other tensordicts with the same structure as the tensordict. An entry that one of them lacks raises
KeyError, unlessdefaultis given.
- Keyword Arguments:
batch_size (Size or list of int, optional) – the batch size of the result, for a
fnthat changes the shape of the leaves: the results must have it as their leading dimensions.fnis then not called onUnbatchedTensorentries, which keep their data and take the new batch size. Defaults toNone, which keeps the batch size of the tensordict.device (device, str or int, optional) – the device of the result. The results of
fnare moved to it.Nonegives a result with no device, which leaves each result wherefnput it. By default, the result has the device of the tensordict.names (list of str, optional) – the names of the batch dimensions of the result, one per dimension. By default, the names of the tensordict are kept, or dropped if
batch_sizeis given.inplace (bool, optional) – if
True, the results are written into the existing leaves of the tensordict (asset_()does), andselfis returned. See In-place operations. Defaults toFalse.default (Any, optional) – the value passed to
fnfor an entry that one ofotherslacks. By default, a missing entry raisesKeyError.filter_empty (bool, optional) – if
True, a nested tensordict with no entry in the result (becausefnreturnedNonefor all its leaves, or because it was already empty) is left out. IfFalse, it is kept, empty. Defaults toNone, which leaves out the nested tensordicts thatfnemptied and keeps those that were already empty. Non-tensor data thatfnis not called on is kept in all cases.propagate_lock (bool, optional) – if
True, the result of a locked tensordict is locked too. Defaults toFalse.call_on_nested (bool, optional) – if
True,fnis called on the top-level entries, nested tensordicts and tensorclasses included, and is responsible for going into them. IfFalse,fnis called on the leaves only. Defaults toFalse.is_leaf (Callable, optional) – called with the type of each entry:
fnis called on the entries for which it returnsTrue, andapplygoes into the others. Defaults toNone, which usesdefault_is_leaf():fnis called on tensors, and non-tensor data is kept unchanged. Passis_leaf_nontensor()to callfnon non-tensor data too.out (TensorDictBase, optional) – a tensordict to write the results into, instead of a new one. When
batch_sizeordeviceis given,outmust have it. For a lazy stack,outmust be a lazy stack too, stacked along any dimension. See the warning below aboutout=self. Defaults toNone.**constructor_kwargs – ignored, with a
FutureWarning. Starting with TensorDict 0.17, the default will change to raising aTypeErrorfor them.
- Returns:
A new tensordict,
outif it is given, orselfifinplace=True.NoneiffnreturnsNonefor every leaf andfilter_emptyis notFalse. Withfilter_empty=None, a tensordict that is already empty gives an empty tensordict.The result has the type of the tensordict for a
TensorDict, a lazy stack and a tensorclass. Other types, for examplePersistentTensorDictor a memory-mapped tensordict, give aTensorDictthat lives in memory. A locked tensordict gives an unlocked result unlesspropagate_lock=True.
Warning
With
out=self, the results are silently wrong iffnreads other entries of the tensordict, which may already be overwritten.Examples
>>> import torch >>> from tensordict import TensorDict >>> td = TensorDict( ... a=-torch.ones(3), ... b=TensorDict(c=torch.ones(3), batch_size=[3]), ... batch_size=[3], ... ) >>> td.apply(lambda x: x + 1)["b", "c"] tensor([2., 2., 2.])
With another tensordict,
fnreceives one leaf of each:>>> td.apply(lambda x, y: x + y, td)["a"] tensor([-2., -2., -2.])
Returning
Noneleaves the entry out:>>> out = td.apply(lambda x: x if x.sum() > 0 else None) >>> list(out.keys(include_nested=True, leaves_only=True)) [('b', 'c')]
A
fnthat changes the shape of the leaves needs abatch_size:>>> td.apply(lambda x: x.unsqueeze(-1), batch_size=[3, 1]).batch_size torch.Size([3, 1])
By default,
fnis not called on non-tensor data:>>> from tensordict import is_leaf_nontensor >>> td = TensorDict(a=torch.zeros(3), b="a string", batch_size=[3]) >>> seen = [] >>> _ = td.apply(lambda x: seen.append(type(x).__name__)) >>> seen ['Tensor'] >>> seen = [] >>> _ = td.apply(lambda x: seen.append(type(x).__name__), is_leaf=is_leaf_nontensor) >>> seen ['Tensor', 'NonTensorData']
Every tensordict class and every tensorclass has this method. For the other methods, see Methods by task.