Repository: pytorch
Issue: Add support for immutable tensors in torch.export
Labels: triaged,oncall: pt2,module: fakeTensor,module: dynamic shapes,oncall: export,module: pt2-dispatcher

### 🚀 The feature, motivation and pitch

I'm working on exporting an object detection model which casts a list of tensor shapes into a tensor, and I'm trying to hint the compiler that it should treat it as a constant in order to avoid unnecessary `GuardOnDataDependentSymNode` errors. The problem is that when the list is casted to a tensor, it's data "unspecializes" and throws `GuardOnDataDependentSymNode` errors (on the linspace line). 


```py
import torch
import torch.nn as nn
import typing
import torch._dynamo as dynamo
import logging

class NetMRE(nn.Module):
    def forward(self, x: typing.List[torch.Tensor]):
        spatial_shapes: typing.List[typing.Tuple[int, int]] = []
        for xi in x:
            spatial_shapes.append(xi.shape[2:])

        spatial_shapes = torch.as_tensor(spatial_shapes, dtype=torch.long)
        reference_points_list = []
        for H, W in spatial_shapes:
            lin = torch.linspace(0.5, H - 0.5, H, dtype=torch.float32) # --- breaks here
            reference_points_list.append(lin)
        return reference_points_list

example_kwargs = {
    "x": [
        torch.rand(1, 3, 64, 64),
        torch.rand(1, 3, 32, 32),
    ],
}
exported_program: torch.export.ExportedProgram = export(
    NetMRE(), (), kwargs=example_kwargs, strict=True,
)
```

### Alternatives

1. The easiest fix is to never cast the list to tensor and refactor all subsequent code that uses the tensor operations on that object. Although this is not a terrible alternative, I feel like it could be easily avoidable with the suggested feature.

2. The hackier solution I've found so far is disable the faketensor creation, but it doesn't work with `strict=True` and it also seems like it would probably break other things.

```py
class NetC2v2(nn.Module):
    def forward(self, x: typing.List[torch.Tensor]):
        spatial_shapes: typing.List[typing.Tuple[int, int]] = []
        for i, xi in enumerate(x):
            spatial_shapes.append(tuple(xi.shape[2:]))
        
        with unset_fake_temporarily():
            with disable_proxy_modes_tracing():
                spatial_shapes_tensor = torch.tensor(spatial_shapes, dtype=torch.long)
        reference_points = self.get_reference_points(spatial_shapes_tensor)
        return reference_points

    @staticmethod
    def get_reference_points(
        spatial_shapes: torch.Tensor,
    ): 
        reference_points_list = []
        for i in range(len(spatial_shapes)):
            with disable_proxy_modes_tracing():
                with unset_fake_temporarily():
                    h = int(spatial_shapes[i][0])
            lin = torch.linspace(0.5, h - 0.5, h, dtype=torch.float32)
            reference_points_list.append(lin)
        return reference_points_list
```

### Additional context

As far as I could see in the codebase, there is support for constant scalar tensors, but couldn't find anything else. 

cc @ezyang @chauhang @penguinwu @eellison @avikchaudhuri @gmagogsfm @zhxchen17 @tugsbayasgalan @angelayi @suo @ydwu4 @zou3519 @bdhirsh @yf225