Sorry for the probably stupid questions but I’m a total newbie here:

if I try to use torch::Tensor I get

fwht.cpp:7:8: error: ‘Tensor’ in namespace ‘torch’ does not name a type

Do I get to use this torch::Tensor only if I write my extension in the ATen native folder inside the pytorch repo and then recompile?

if I use at::Tensor everything compiles correctly but when I try to use my Python binding fwht.forward(torch.randn(10, 512)) I get

RuntimeError: copy_from does not support automatic differentiation; use copy_ instead (_s_copy_from at /home/iacolippo/pytorch/torch/csrc/autograd/VariableTypeManual.cpp:265)

From the README and the guide on how to write C++ extensions 3 I understood that it’s not really a problem if autodiff breaks provided that you define a backward function, which I’m doing here.
#include <torch/extension.h>
#include<cmath>
#include <iostream>
#include <vector>


at::Tensor fwht_forward(
    at::Tensor input
    ) {
    auto n_samples = input.size(0);
    auto n_features = input.size(1);
    auto G = n_features / 2;
    auto M = 2;

    at::Tensor temp = at::zeros({n_samples, G, 2});
    for (auto i = 0; i < n_samples; i++) {
        for (auto j = 0; j < n_features; j = j + 2) {
            temp[i][j/2][0] = input[i][j] + input[i][j+1];
            temp[i][j/2][1] = input[i][j] - input[i][j+1];
        }
    }
    at::Tensor res = at::empty({n_samples, G, 2});
    res.copy_(temp);

    for (auto i = 2; i < std::log2(n_features) + 1; i++) {
        temp = at::zeros({n_samples, G / 2, M * 2});
        auto res_acc = res.accessor<float, 3>();
        auto t_a = temp.accessor<float, 3>();
        for (auto j = 0; j < res.size(0); j++) {
            for (auto k = 0; k < G; k = k + 2) {
                for (auto l = 0; l < res.size(2); l = l + 4) {
                    t_a[j][k/2][l] = res_acc[j][k][l/2] + res_acc[j][k+1][l/2];
                    t_a[j][k/2][l+1] = res_acc[j][k][l/2] - res_acc[j][k+1][l/2];
                    t_a[j][k/2][l+2] = res_acc[j][k][l/2+1] - res_acc[j][k+1][l/2+1];
                    t_a[j][k/2][l+3] = res_acc[j][k][l/2+1] + res_acc[j][k+1][l/2+1];
                }
            }
        }
        res.copy_(temp);
        G = G / 2;
        M = M * 2;
    }

    auto temp_acc = temp.accessor<float, 3>();
    at::Tensor output = at::zeros({n_samples, n_features});
    for (auto m = 0; m < n_samples; m++) {
        for (auto n = 0; n < temp.sizes()[2]; n++) {
            output[m][n] = temp_acc[m][0][n];
        }
    }
    return output * pow(std::sqrt(n_features), -1);
}


at::Tensor fwht_backward(
    at::Tensor input
    ) {
    auto n_samples = input.size(0);
    auto n_features = input.size(1);
    auto G = n_features / 2;
    auto M = 2;

    at::Tensor temp = at::zeros({n_samples, G, 2});
    for (auto i = 0; i < n_samples; i++) {
        for (auto j = 0; j < n_features; j = j + 2) {
            temp[i][j/2][0] = input[i][j] + input[i][j+1];
            temp[i][j/2][1] = input[i][j] - input[i][j+1];
        }
    }
    at::Tensor res = at::empty({n_samples, G, 2});
    res.copy_(temp);

    for (auto i = 2; i < std::log2(n_features) + 1; i++) {
        temp = at::zeros({n_samples, G / 2, M * 2});
        auto res_acc = res.accessor<float, 3>();
        auto t_a = temp.accessor<float, 3>();
        for (auto j = 0; j < res.size(0); j++) {
            for (auto k = 0; k < G; k = k + 2) {
                for (auto l = 0; l < res.size(2); l = l + 4) {
                    t_a[j][k/2][l] = res_acc[j][k][l/2] + res_acc[j][k+1][l/2];
                    t_a[j][k/2][l+1] = res_acc[j][k][l/2] - res_acc[j][k+1][l/2];
                    t_a[j][k/2][l+2] = res_acc[j][k][l/2+1] - res_acc[j][k+1][l/2+1];
                    t_a[j][k/2][l+3] = res_acc[j][k][l/2+1] + res_acc[j][k+1][l/2+1];
                }
            }
        }
        res.copy_(temp);
        G = G / 2;
        M = M * 2;
    }

    auto temp_acc = temp.accessor<float, 3>();
    at::Tensor output = at::zeros({n_samples, n_features});
    for (auto m = 0; m < n_samples; m++) {
        for (auto n = 0; n < temp.sizes()[2]; n++) {
            output[m][n] = temp_acc[m][0][n];
        }
    }
    return output * pow(std::sqrt(n_features), -1);
}

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
  m.def("forward", &fwht_forward, "FWHT forward");
  m.def("backward", &fwht_backward, "FWHT backward");
}

what’s the issue with this copy_?