A function to cache the expensive input data transform operations so that huge data sets (larger than computer memory) can be processed on the fly as needed, and intermediate results written to disk for future use. Args: item_transformed: The cur
(self, item_transformed)
| 370 | return item_transformed |
| 371 | |
| 372 | def _cachecheck(self, item_transformed): |
| 373 | """ |
| 374 | A function to cache the expensive input data transform operations |
| 375 | so that huge data sets (larger than computer memory) can be processed |
| 376 | on the fly as needed, and intermediate results written to disk for |
| 377 | future use. |
| 378 | |
| 379 | Args: |
| 380 | item_transformed: The current data element to be mutated into transformed representation |
| 381 | |
| 382 | Returns: |
| 383 | The transformed data_element, either from cache, or explicitly computing it. |
| 384 | |
| 385 | Warning: |
| 386 | The current implementation does not encode transform information as part of the |
| 387 | hashing mechanism used for generating cache names when `hash_transform` is None. |
| 388 | If the transforms applied are changed in any way, the objects in the cache dir will be invalid. |
| 389 | |
| 390 | """ |
| 391 | hashfile = None |
| 392 | if self.cache_dir is not None: |
| 393 | data_item_md5 = self.hash_func(item_transformed).decode("utf-8") |
| 394 | data_item_md5 += self.transform_hash |
| 395 | hashfile = self.cache_dir / f"{data_item_md5}.pt" |
| 396 | |
| 397 | if hashfile is not None and hashfile.is_file(): # cache hit |
| 398 | try: |
| 399 | return torch.load(hashfile, weights_only=self.weights_only) |
| 400 | except PermissionError as e: |
| 401 | if sys.platform != "win32": |
| 402 | raise e |
| 403 | except (UnpicklingError, RuntimeError) as e: # corrupt or unloadable cached files are recomputed |
| 404 | if "Invalid magic number; corrupt file" in str(e) or isinstance(e, UnpicklingError): |
| 405 | warnings.warn(f"Corrupt cache file detected: {hashfile}. Deleting and recomputing.") |
| 406 | hashfile.unlink() |
| 407 | else: |
| 408 | raise e |
| 409 | |
| 410 | _item_transformed = self._pre_transform(deepcopy(item_transformed)) # keep the original hashed |
| 411 | if hashfile is None: |
| 412 | return _item_transformed |
| 413 | try: |
| 414 | # NOTE: Writing to a temporary directory and then using a nearly atomic rename operation |
| 415 | # to make the cache more robust to manual killing of parent process |
| 416 | # which may leave partially written cache files in an incomplete state |
| 417 | with tempfile.TemporaryDirectory() as tmpdirname: |
| 418 | temp_hash_file = Path(tmpdirname) / hashfile.name |
| 419 | torch.save( |
| 420 | obj=convert_to_tensor(_item_transformed, convert_numeric=False, track_meta=self.track_meta), |
| 421 | f=temp_hash_file, |
| 422 | pickle_module=look_up_option(self.pickle_module, SUPPORTED_PICKLE_MOD), |
| 423 | pickle_protocol=self.pickle_protocol, |
| 424 | ) |
| 425 | if temp_hash_file.is_file() and not hashfile.is_file(): |
| 426 | # On Unix, if target exists and is a file, it will be replaced silently if the user has permission. |
| 427 | # for more details: https://docs.python.org/3/library/shutil.html#shutil.move. |
| 428 | try: |
| 429 | shutil.move(str(temp_hash_file), hashfile) |
no test coverage detected