TensorDictBase.memmap#
- TensorDictBase.memmap(prefix: str | Path | None = None, copy_existing: bool = False, *, num_threads: int = 0, return_early: bool = False, share_non_tensor: bool = False, existsok: bool = True, robust_key: bool | None = True, archive: bool | None = None, compression: str | int | None = None, atomic: bool = False) Self#
Writes every leaf to a memory-mapped file and returns a new tensordict of them.
The tensordict is not changed: the result holds new
MemoryMappedTensorleaves. Each leaf is written to<prefix>/<key>.memmap, each nested tensordict to a subdirectory, and each level has ameta.jsonfile. Read the files back withload_memmap().save()anddumps()call this method, andmemmap_()writes in place. See Save and load tensordicts.The result is locked (see Locking and temporary changes): you can write into its leaves in place, but you cannot add, remove or replace an entry. Once it is unlocked,
is_memmap()returnsFalse.- Parameters:
prefix (str or Path, optional) – the directory to write to. If it ends with
".tdz", a single archive file is written instead (seearchive). Defaults toNone, which writes into the directory of the tensordict if it is already memory-mapped there, and otherwise into anonymous shared memory, which has no file name and lasts as long as the process.copy_existing (bool, optional) – if
False, a leaf that is already a memory-mapped tensor with a file at another path raises aRuntimeError, so that data on disk is not duplicated by accident. IfTrue, the file is copied to the new path. Defaults toFalse.
- Keyword Arguments:
num_threads (int, optional) – the number of threads that write the files.
0and1write them one after the other in the calling thread. Threads help with a few large leaves and slow down many small ones. Defaults to0.return_early (bool, optional) – if
Trueandnum_threads > 1, returns aTensorDictFutureat once, while the threads write the files:future.result()waits for them and returns the tensordict. Not supported for an archive. Defaults toFalse.share_non_tensor (bool, optional) – if
True, non-tensor data is shared between the processes of the node, so that an in-place write of a non-tensor entry in one process is seen by the others. Many non-tensor leaves (for example a large stack of non-tensor data) can use up the memory. Defaults toFalse.existsok (bool, optional) – if
False, a file that already exists at the path of a leaf (or at the archive path) raises aRuntimeError. IfTrue, it is overwritten. Defaults toTrue.robust_key (bool, optional) – if
True, keys are percent-encoded in file and directory names ("a/b"is written toa%2Fb.memmap), so that every file stays insideprefix. IfFalse, keys are used as file names unchanged, as in the legacy layout: do not use it with keys you do not trust.Noneis the same asTrue. Defaults toTrue.archive (bool, optional) – if
True,prefixis a file, and the tensordict is written to it as an archive: a zip file whose entries are the files of the directory layout, with uncompressed and aligned tensor payloads. Defaults toNone, which writes an archive ifprefixends with".tdz".compression (str or int, optional) – the compression of the archive entries:
"stored","deflate","bzip2","lzma", or azipfileconstant. A compressed leaf is decompressed in memory when it is loaded, instead of being memory-mapped. Only valid for an archive. Defaults toNone, which stores the entries uncompressed.atomic (bool, optional) – if
True, the files are written to a new directory next toprefix, which is then renamed toprefix, so that an error or a crash during the write leavesprefixas it was. The new directory is removed if the write fails (but not after a crash). An existing directory atprefixis replaced as a whole once the new one is complete, so files that the tensordict does not write are removed: it must be empty or hold a saved tensordict (ameta.jsonfile). Readers see the old or the new directory, except for the short time between two renames, during whichprefixis missing. The write needs about twice the disk space of the tensordict while it runs, and a leaf that is already memory-mapped to a file is copied, which needscopy_existing=True. The files are not synced to the disk, so this guards against a killed process, not against a power failure. Not supported withreturn_early=True, nor for a directory on Windows, where a directory that holds open files cannot be renamed. An archive is always written this way. Defaults toFalse.
- Returns:
A new memory-mapped tensordict, or a
TensorDictFutureof it ifreturn_early=Trueandnum_threads > 1.- Raises:
RuntimeError – if a leaf already has a file elsewhere and
copy_existing=False, if a file exists andexistsok=False, or withatomic=True, ifprefixis a non-empty directory andexistsok=False, or if it holds no saved tensordict.NotADirectoryError – if
atomic=Trueandprefixis a file.ValueError – if
compressionis given without an archive, or if an archive oratomic=Trueis requested withoutprefix.NotImplementedError – if
return_early=Truefor an archive or withatomic=True, oratomic=Truefor a directory on Windows.
Note
For an archive, the result is
load_memmap(prefix): its leaves are views into one copy-on-write mapping of the file, so in-place writes do not reach the file, and it is not locked. Archives are written in one pass, sonum_threadsdoes not speed them up. An existing archive is replaced by a new file: a symlink is followed, but other hard links keep the old content.pack_memmap()andunpack_memmap()convert between archives and directories.Examples
>>> import os >>> import tempfile >>> import torch >>> from tensordict import TensorDict >>> td = TensorDict( ... obs=torch.zeros(3, 4), ... next=TensorDict(reward=torch.ones(3, 1), batch_size=[3]), ... batch_size=[3], ... ) >>> with tempfile.TemporaryDirectory() as path: ... mm = td.memmap(path) ... print(type(mm["obs"]).__name__, mm.is_locked) ... print(sorted(os.listdir(path))) MemoryMappedTensor True ['meta.json', 'next', 'obs.memmap']
Every tensordict class and every tensorclass has this method. For the other methods, see Methods by task.