Repository: pytorch
Issue: path\tp\torch\torch.h(14,1): fatal error C1001: Internal compiler error.
Labels: module: dependency bug,module: windows,module: cpp,triaged

### 🐛 Describe the bug

I try to build my application with new C++20 features but they are currently bad supported and compiler throw me such errors

### Versions

## Error using Libtorch with MSVC and C++20 modules

I tried to build my project using MSBuild and MSVC and found out that I need several compile definitions, to resurrect functions from C++17 and make them not deprecated and compiler thrown me such output:
```
1>path\to\libtorch\include\torch\csrc\api\include\torch\torch.h(9,1): fatal error C1001: Internal compiler error.
1>d:\a01\_work\49\s\src\vctools\Compiler\CxxFE\sl\p1\c\module\writer.cpp:6066: sorry: not yet implemented
1>(compiler file 'd:\a01\_work\49\s\src\vctools\Compiler\CxxFE\sl\p1\c\module\utilities.h', line 34)
1> To work around this problem, try simplifying or changing the program near the locations listed above.
1>If possible please provide a repro here: https://developercommunity.visualstudio.com
1>Please choose the Technical Support command on the Visual C++
1> Help menu, or open the Technical Support help file for more information
1>Done building project "basic-neural-win.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
```

I have such code in my C++20 module:
```
export module Classification;

import <opencv2/opencv.hpp>;
import <torch/torch.h>;
import <filesystem>;
import <memory>;
import <string>;
import <tuple>;

export namespace classification {

namespace fs = std::filesystem;

struct ConvNetImpl : public torch::nn::Module {
  ConvNetImpl(int64_t channels, int64_t height, int64_t width);

  torch::Tensor forward(torch::Tensor x);

  int64_t GetFlattenLength(int64_t channels, int64_t height, int64_t width);

 private:
  torch::nn::Conv2d conv1, conv2, conv3;
  int64_t flatten_length;
  torch::nn::Linear lin1, lin2, lin3, lin4, lin5;
};

TORCH_MODULE(ConvNet);

class CustomDataset : public torch::data::Dataset<CustomDataset> {
 private:
  std::vector<std::tuple<std::string, int64_t>> dataset_;
  std::vector<std::tuple<std::string, int64_t>> ReadDataset(
      std::string dataset_location);

 public:
  explicit CustomDataset(std::string dataset_root_dir);

  torch::data::Example<> get(size_t index) override;

  torch::optional<size_t> size() const override;
};

template <typename ModuleType>
class Classifier {
 public:
  Classifier() = delete;
  Classifier(ModuleType const model);
  template <typename... ModelParams>
  Classifier(std::string model_path, ModelParams... model_params);

  template <typename... ModelParams>
  void LoadModel(ModuleType const model, ModelParams... model_params);
  template <typename... ModelParams>
  void LoadModel(std::string model_path, ModelParams... model_params);

  int Classify(std::string image_path);
  int Classify(cv::Mat const image);
  template <typename DatasetType>
  void Train(std::shared_ptr<torch::data::Dataset<DatasetType>> const dataset,
             std::string model_save_dir);

 private:
  ModuleType model_;
};

using namespace std::string_literals;

template <typename ModuleType>
Classifier<ModuleType>::Classifier(ModuleType const model) : model_(model) {}

template <typename ModuleType>
template <typename... ModelParams>
Classifier<ModuleType>::Classifier(std::string model_path,
                                   ModelParams... model_params)
    : model_(ModuleType(model_params...)) {
  torch::load(model_, model_path);
}

template <typename ModuleType>
template <typename... ModelParams>
void Classifier<ModuleType>::LoadModel(ModuleType const model,
                                       ModelParams... model_params) {
  model_(model_params...);
}

template <typename ModuleType>
template <typename... ModelParams>
void Classifier<ModuleType>::LoadModel(std::string model_path,
                                       ModelParams... model_params) {
  model_(model_params...);
  torch::load(model_, model_path);
}

template <typename ModuleType>
int Classifier<ModuleType>::Classify(std::string image_path) {
  cv::Mat image = cv::imread(image_path);

  torch::Tensor image_tensor = torch::from_blob(
      image.data, {1, image.rows, image.cols, 3}, torch::kByte);
  image_tensor = image_tensor.permute({0, 3, 1, 2});  // convert to CxHxW
  image_tensor = image_tensor.to(torch::kF32);

  torch::Tensor log_probability = model_(image_tensor);
  torch::Tensor probability = torch::exp(log_probability);

  return torch::argmax(probability).item<int>();
}

template <typename ModuleType>
int Classifier<ModuleType>::Classify(cv::Mat const image) {
  torch::Tensor image_tensor = torch::from_blob(
      image.data, {1, image.rows, image.cols, 3}, torch::kByte);
  image_tensor = image_tensor.permute({0, 3, 1, 2});  // convert to CxHxW
  image_tensor = image_tensor.to(torch::kF32);

  torch::Tensor log_probability = model_(image_tensor);
  torch::Tensor probability = torch::exp(log_probability);

  return torch::argmax(probability).item<int>();
}

template <typename ModuleType>
template <typename DatasetType>
void Classifier<ModuleType>::Train(
    std::shared_ptr<torch::data::Dataset<DatasetType>> const dataset,
    std::string model_save_dir) {
  int64_t batch_size = 64;
  auto data_loader =
      torch::data::make_data_loader<torch::data::samplers::RandomSampler>(
          dataset, batch_size);

  torch::optim::Adam optimizer(model_->parameters(),
                               torch::optim::AdamOptions(1e-3));

  int64_t n_epochs = 30;
  int64_t log_interval = 10;
  int dataset_size = dataset.size().value();

  float best_mse = std::numeric_limits<float>::max();

  for (int epoch = 1; epoch <= n_epochs; epoch++) {
    float mse = 0.f;
    int count = 0;

    for (size_t batch_idx = 0; auto& batch : *data_loader) {
      auto imgs = batch.data;
      auto labels = batch.target.squeeze();

      imgs = imgs.to(torch::kF32);
      labels = labels.to(torch::kInt64);

      optimizer.zero_grad();
      auto output = model(imgs);
      auto loss = torch::nll_loss(output, labels);

      loss.backward();
      optimizer.step();

      mse += loss.template item<float>();

      batch_idx++;
      if (batch_idx % log_interval == 0) {
        std::printf("\rTrain Epoch: %d/%ld [%5ld/%5d] Loss: %.4f", epoch,
                    n_epochs, batch_idx * batch.data.size(0), dataset_size,
                    loss.template item<float>());
      }

      count++;
    }

    mse /= (float)count;
    printf(" Mean squared error: %f\n", mse);

    if (mse < best_mse) {
      torch::save(model_, model_save_dir + "/best_model.pt");
      best_mse = mse;
    }
  }
}

template class Classifier<ConvNet>;

ConvNetImpl::ConvNetImpl(int64_t channels, int64_t height, int64_t width)
    : conv1(torch::nn::Conv2dOptions(3, 32, 4).stride(2)),
      conv2(torch::nn::Conv2dOptions(32, 64, 4).stride(2)),
      conv3(torch::nn::Conv2dOptions(64, 128, 4).stride(2)),
      flatten_length(GetFlattenLength(channels, height, width)),
      lin1(flatten_length, 512),
      lin2(512, 256),
      lin3(256, 128),
      lin4(128, 64),
      lin5(64, 9) {
  register_module("conv1", conv1);
  register_module("conv2", conv2);
  register_module("conv3", conv3);
  register_module("lin1", lin1);
  register_module("lin2", lin2);
  register_module("lin3", lin3);
  register_module("lin4", lin4);
  register_module("lin5", lin5);
};

torch::Tensor ConvNetImpl::forward(torch::Tensor x) {
  x = torch::relu(torch::max_pool2d(conv1(x), 2));
  x = torch::relu(torch::max_pool2d(conv2(x), 2));
  x = torch::relu(torch::max_pool2d(conv3(x), 2));

  // Flatten.
  x = x.view({-1, flatten_length});

  x = torch::relu(lin1(x));
  x = torch::relu(lin2(x));
  x = torch::relu(lin3(x));
  x = torch::relu(lin4(x));
  x = torch::log_softmax(lin5(x), 1);

  return x;
};

int64_t ConvNetImpl::GetFlattenLength(int64_t channels, int64_t height,
                                      int64_t width) {
  torch::Tensor x = torch::zeros({1, channels, height, width});
  x = torch::max_pool2d(conv1(x), 2);
  x = torch::max_pool2d(conv2(x), 2);
  x = torch::max_pool2d(conv3(x), 2);

  return x.numel();
}

CustomDataset::CustomDataset(std::string dataset_root_dir)
    : dataset_(ReadDataset(dataset_root_dir)) {}

torch::data::Example<> CustomDataset::get(size_t index) {
  std::string file_location = std::get<0>(dataset_[index]);
  int64_t label = std::get<1>(dataset_[index]);
  cv::Mat img = cv::imread(file_location);
  torch::Tensor img_tensor =
      torch::from_blob(img.data, {img.rows, img.cols, 3}, torch::kByte).clone();
  img_tensor = img_tensor.permute({2, 0, 1});  // convert to CxHxW

  torch::Tensor label_tensor = torch::full({1}, label);

  return {img_tensor, label_tensor};
}

torch::optional<size_t> CustomDataset::size() const { return dataset_.size(); }

std::vector<std::tuple<std::string, int64_t>> CustomDataset::ReadDataset(
    std::string dataset_location) {
  std::vector<std::tuple<std::string, int64_t>> dataset;

  for (int64_t current_label = 0;
       auto const& images_group :
       fs::directory_iterator(fs::path(dataset_location))) {
    for (auto const& image : fs::directory_iterator(images_group)) {
      dataset.push_back({image.path().string(), current_label});
    }

    current_label++;
  }

  return dataset;
}

}

```

If you can please remove deprecated functions there several places where they used, I would provide my own pull request

cc @peterjc123 @mszhanyi @skyline75489 @nbcsm @jbschlosser