Hello,
I am a pytorch beginner and wanted to implement a really simple module (autograd and module extension) reprensenting an affine transformation.
I am however struggling with my code which returns the following error:
‘Variable’ object has no attribute ‘numpy’
It comes from the fact (I guess) that the type of input is tuple whereas I am expecting input to be a tuple.
I am pretty sure I am doing many stupid things and if somebody can help me / guide me it will be greatly appreciate. Here is the implementation I made (get prepared … sorry)
import torch
from torch.autograd import Function
from torch.autograd import Variable
import numpy as np
from scipy.signal import convolve2d, correlate2d
from torch.nn.modules.module import Module
from torch.nn.parameter import Parameter
##
## Inherit from Function
class RigidTransformationFunction(Function):
# Both forward and backward are @staticmethods
def forward(self, input, param):
# Affine transformation
# rotation parametrised by 3 rotation angles
R_ = Rotation3D()
R_.rot3D(param[0,0], param[0,1], param[0,2])
t = torch.Tensor(3, 1)
t[0,0] = param[0,3]
t[1,0] = param[0,4]
t[2,0] = param[0,5]
r = torch.from_numpy(R_.R)
xyz_ = r @ input.double() + t.double()
self.save_for_backward(input)
return torch.DoubleTensor(xyz_)
def backward(self,param_grad):
# derived wrt affine parameters
input = self.saved_tensors
# rotation parametrised by 3 rotation angles
R_ = Rotation3D()
R_.rot3D_grad_rx(param_grad[0,0], param_grad[0,1], param_grad[0,2])
R_.rot3D_grad_ry(param_grad[0,0], param_grad[0,1], param_grad[0,2])
R_.rot3D_grad_rz(param_grad[0,0], param_grad[0,1], param_grad[0,2])
r = torch.from_numpy(R_.R_x)
grad_rx = r @ input.double()
r = torch.from_numpy(R_.R_y)
grad_ry = r @ input.double()
r = torch.from_numpy(R_.R_z)
grad_rz = r @ input.double()
grad_tx = 1
grad_ty = 1
grad_tz = 1
return torch.FloatTensor(grad_rx), torch.FloatTensor(grad_ry), torch.FloatTensor(grad_rz), torch.FloatTensor(grad_tx), torch.FloatTensor(grad_ty), torch.FloatTensor(grad_tz)
class RigidTransformation(Module):
def __init__(self):
super(RigidTransformation, self).__init__()
self.form = 'rotation_angle'
self.param = Parameter(torch.randn(1, 6))
def forward(self, input):
return RigidTransformationFunction()(input, self.param)
class Rotation3D:
def __init__(self):
self.R = []
self.R_x = []
self.R_y = []
self.R_z = []
def rot3D(self,rx,ry,rz):
Rx = np.array( [ [ 1 , 0 , 0 ] ,
[ 0 , np.cos(rx) , -np.sin( rx ) ] ,
[ 0 , np.sin( rx ) , np.cos( rx ) ] ] )
Ry = np.array( [ [ np.cos( ry ) , 0 , np.sin( ry ) ] ,
[ 0 , 1 , 0 ] ,
[ -np.sin( ry ) , 0 , np.cos( ry ) ] ] )
Rz = np.array( [ [ np.cos( rz ) , -np.sin( rz ) , 0 ] ,
[ np.sin( rz ) , np.cos( rz ) , 0 ] ,
[ 0 , 0 , 1 ] ] )
self.R = Rz.dot(Ry.dot(Rx))
def rot3D_grad_rx(self,rx,ry,rz):
Rx = np.matrix( [ [ 0 , 0 , 0 ] ,
[ 0 , -np.sin( rx ) , -np.cos( rx ) ] ,
[ 0 , np.cos( rx ) , -np.sin( rx ) ] ] )
Ry = np.matrix( [ [ np.cos( ry ) , 0 , np.sin( ry ) ] ,
[ 0 , 1 , 0 ] ,
[ -np.sin( ry ) , 0 , np.cos( ry ) ] ] )
Rz = np.matrix( [ [ np.cos( rz ) , -np.sin( rz ) , 0 ] ,
[ np.sin( rz ) , np.cos( rz ) , 0 ] ,
[ 0 , 0 , 1 ] ] )
self.R_x = Rz.dot(Ry.dot(Rx))
def rot3D_grad_ry(self,rx,ry,rz):
Rx = np.matrix( [ [ 1 , 0 , 0 ] ,
[ 0 , np.cos( rx ) , -np.sin( rx ) ] ,
[ 0 , np.sin( rx ) , np.cos( rx ) ] ] )
Ry = np.matrix( [ [ -np.sin( ry ) , 0 , np.cos( ry ) ] ,
[ 0 , 0 , 0 ] ,
[ -np.cos( ry ) , 0 , -np.sin( ry ) ] ] )
Rz = np.matrix( [ [ np.cos( rz ) , -np.sin( rz ) , 0 ] ,
[ np.sin( rz ) , np.cos( rz ) , 0 ] ,
[ 0 , 0 , 1 ] ] )
self.R_y = Rz.dot(Ry.dot(Rx))
def rot3D_grad_rz(self,rx,ry,rz):
Rx = np.matrix( [ [ 1 , 0 , 0 ] ,
[ 0 , np.cos( rx ) , -np.sin( rx ) ] ,
[ 0 , np.sin( rx ) , np.cos( rx ) ] ] )
Ry = np.matrix( [ [ np.cos( ry ) , 0 , np.sin( ry ) ] ,
[ 0 , 1 , 0 ] ,
[ -np.sin( ry ) , 0 , np.cos( ry ) ] ] )
Rz = np.matrix( [ [ -np.sin( rz ) , -np.cos( rz ) , 0 ] ,
[ np.cos( rz ) , -np.sin( rz ) , 0 ] ,
[ 0 , 0 , 0 ] ] )
self.R_z = Rz.dot(Ry.dot(Rx))
rT = RigidTransformation()
print(list(rT.parameters()))
input = Variable(torch.randn(3, 5), requires_grad=True)
print(input)
output = rT(input)
print(output)
print('______________')
output.backward(torch.randn(8, 8))
print(input.grad)
print('______________')