Minimize angle in pytorch
I'm trying to figure out how to minimize a scalar in pytorch that represents the angle of an axis/angle rotation. My target is a sample set of 3D vectors, my input is the target rotated by a particular axis/angle rotation (plus some gaussian noise). The axis is known and fixed. I want to find the angle using pytorch. 

What I have so far is this nn.Module:

class AngleModel(torch.nn.Module):
    def __init__(self):
        super(AngleModel, self).__init__()
        self.angle = nn.Parameter(Variable(torch.Tensor([0.0]), requires_grad=True))
        self.qw = torch.cos(self.angle / 2.)
        self.qx = 0.0
        self.qy = 0.0
        self.qz = torch.sin(self.angle / 2.)

    def forward(self, input):
        matrix_np = transform_from_pq([0, 0, 0, self.qw, self.qx, self.qy, self.qz])
        matrix = torch.from_numpy(matrix_np)
        input_ext = torch.cat((input, torch.ones(input.size(0)).reshape(-1, 1)), 1)
        output = torch.matmul(input_ext.float(), matrix.float())
        return output[:, :3]


However using this in an optimizer fails because model.parameters() returns an empty list (i.e. "empty" generator). 

I'm completely new to pytorch. What am I doing wrong? 

Relevant code

Initialization: 

def _init_model(self):
    self.model = AngleModel()
    self.crit = torch.nn.MSELoss()
    l_rate = 0.01
    print(list(self.model.parameters()))
    self.optim = torch.optim.SGD(self.model.parameters(), lr = l_rate)
    self.epochs = 2000


Learning function: 

for epoch in range(self.epochs):
    inputs = torch.from_numpy(normalize(input))
    labels = torch.from_numpy(normalize(target))
    _x = Variable(inputs, requires_grad = True) # without it complains about no grad_fn
    _y = Variable(labels)
    self.optim.zero_grad()

    outputs = self.model.forward(_x)
    loss = self.crit(outputs, _y)
    loss.backward()
    self.optim.step()
    print("Epoch %6d loss %05.3f; %s" % (epoch, loss.data[0], self.model.angle))


Update 1:


Code of the Module updated
Surrounding code added
This at least does not throw any errors anymore but also does not optimize angle


Here are the necessary changes to the AngleModel class to make it work:

class AngleModel(nn.Module):
    def __init__(self):
        super(AngleModel, self).__init__()
        self.angle = nn.Parameter(torch.tensor(0.0))

    def forward(self, input):
        qw = torch.cos(self.angle / 2.)
        qx = 0.0
        qy = 0.0
        qz = torch.sin(self.angle / 2.)

        matrix = torch.zeros(3, 3)

        matrix[0, 0] = 1. - 2. * qy ** 2 - 2. * qz ** 2
        matrix[1, 1] = 1. - 2. * qx ** 2 - 2. * qz ** 2
        matrix[2, 2] = 1. - 2. * qx ** 2 - 2. * qy ** 2

        matrix[0, 1] = 2. * qx * qy - 2. * qz * qw
        matrix[1, 0] = 2. * qx * qy + 2. * qz * qw

        matrix[0, 2] = 2. * qx * qz + 2 * qy * qw
        matrix[2, 0] = 2. * qx * qz - 2 * qy * qw

        matrix[1, 2] = 2. * qy * qz - 2. * qx * qw
        matrix[2, 1] = 2. * qy * qz + 2. * qx * qw

        output = torch.matmul(input, matrix)
        return output


Among others the main reason that it hadn't been working before was that the graph wasn't consistent due to the intermediate use of numpy. Furthermore the quaternion components qw..qz had been calculated only once in the __init__ method. Their calculation had to move to the forward step too. 
