Repository: pytorch
Issue: Rename C++ Serialization APIs
Labels: module: serialization,triaged

Since #30108 we can pass values in the pickle format produced by `torch.save` to C++ and vice versa, so C++ can read values saved in Python and Python can read values saved in C++. These have been hidden behind the confusingly named `torch::pickle_save` and `torch::pickle_load` (and also are not in the C++ docs), while `torch::save` and `torch::load` uses the "jit" serialization format, which is a similar binary but with some extra jit-specific stuff. Plus to add to the fun torch.package has another Python-only pickle format used by [`PackageExporter.save_pickle`](https://github.com/pytorch/pytorch/blob/master/torch/package/package_exporter.py#L531).

| Method                                  | Format                                                       |
| --------------------------------------- | ------------------------------------------------------------ |
| torch.save / torch.load                 | Zip file (pickle + tensors)                                  |
| torch.jit.save / torch.jit.load         | Zip file with TorchScript-specific items (e.g. `constants.pkl`) |
| torch::save / torch::load               | TorchScript Zip file                                         |
| torch::pickle_save / torch::pickle_load | Compatible with torch.save / torch.load                      |
| torch::jit::load                        | Consumes torch.jit.save binaries                             |
| PackageExporter.save_pickle             | Plain pickle w/ custom Python pickle                         |

`torch::{save,load}` implement serialization in a hacky way on top of how the jit serialization already works, and were added way before any of these other methods. They are pretty much obsolete now and should be replaced with `torch::pickle_save`, which can do everything they can do with less cruft (i.e. no jit-specific stuff to serialize), but they've been in PyTorch for a while so we can't remove them without breaking BC for C++ users. They also differ semantically from `torch.save`, which just pickles whatever you pass in; instead they are aware of various C++ API concepts (each of which have to implement their own saving semantics) and how to extract tensors:

`ag 'serialize::OutputArchive& operator' -C 3`

<details>

  ```cpp
  torch/csrc/api/include/torch/data/datasets/stateful.h
47-
48-/// Serializes a statefulDataset to `OutputArchive`.
49-template <typename... Args>
50:serialize::OutputArchive& operator<<(
51-    serialize::OutputArchive& archive,
52-    const StatefulDataset<Args...>& statefulDataset) {
53-  statefulDataset.save(archive);

torch/csrc/api/include/torch/data/samplers/serialize.h
8-namespace samplers {
9-/// Serializes a `Sampler` into an `OutputArchive`.          
10-template <typename BatchRequest>
11:serialize::OutputArchive& operator<<(
12-    serialize::OutputArchive& archive,
13-    const Sampler<BatchRequest>& sampler) {
14-  sampler.save(archive);

torch/csrc/api/include/torch/nn/pimpl.h
174-
175-/// Serializes a `ModuleHolder` into an `OutputArchive`.   
176-template <typename ModuleType>
177:serialize::OutputArchive& operator<<(
178-    serialize::OutputArchive& archive,
179-    const nn::ModuleHolder<ModuleType>& module) {
180-  return archive << module.ptr();

torch/csrc/api/include/torch/nn/module.h
602-};
603-
604-/// Serialize a `Module` pointer into an `OutputArchive`.  
605:TORCH_API serialize::OutputArchive& operator<<(
606-    serialize::OutputArchive& archive,
607-    const std::shared_ptr<nn::Module>& module);
608-

torch/csrc/api/include/torch/optim/optimizer.h
178-   we skip c10::nullopt values when serializing the param state. */
179-
180-/// Serializes an `Optimizer` into an `OutputArchive`.     
181:TORCH_API serialize::OutputArchive& operator<<(
182-    serialize::OutputArchive& archive,
183-    const Optimizer& optimizer);
184-

torch/csrc/api/include/torch/serialize/tensor.h
4-#include <torch/types.h>
5-
6-namespace torch {
7:inline serialize::OutputArchive& operator<<(                 
8-    serialize::OutputArchive& archive,
9-    const Tensor& tensor) {
10-  archive.write("0", tensor);                               

torch/csrc/api/src/nn/module.cpp                               
395-  return stream;
396-}
397-
398:serialize::OutputArchive& operator<<(                      
399-    serialize::OutputArchive& archive,
400-    const std::shared_ptr<nn::Module>& module) {           
401-  TORCH_CHECK(module != nullptr, "Cannot serialize empty module");

torch/csrc/api/src/optim/optimizer.cpp                         
165-void Optimizer::load(serialize::InputArchive& archive) {}  
166-
167-/// Serializes an `Optimizer` into an `OutputArchive`.     
168:serialize::OutputArchive& operator<<(
169-    serialize::OutputArchive& archive,
170-    const Optimizer& optimizer) {
171-  optimizer.save(archive);
  ```

</details>



Ideally `torch::pickle_save` would be named `torch::save` to correspond with `torch.save`, since they produce the same format, and we could get rid of the old `torch::save`. I don't see a way for us to make this the case without breaking BC in some nasty way, since users may end up with code that compiles after we change it but silently produces a new format. #64410 tries to work around this with `std::enable_if` only if someone explicitly passes in an `IValue` which works but is not the most ergonomic. We could deprecate the old `torch::save` in the upcoming release with a link on migrating to the new API.


cc @mruberry @ezyang @suo