Hi, recently I was trying to reimplement in PyTorch some paper where they implement new way of using kernels: https://www.sciencedirect.com/science/article/abs/pii/S1051200419301873 and before this project, I have only been doing with the kernels and layers supported by Pytorch. In this case I am supposed to add new parameters that will be trained along with the rest of the regular layers, but I feel that I am not doing something properly since parameters are not being updated.
class PointPlaneResnet(nn.Module):
''' PointPlaneNet-based encoder network with ResNet blocks. \n
Args:
c_dim (int): dimension of latent code c, defined by config's model.c_dim = 512
dim (int): input points dimension, in our case
hidden_dim (int): hidden dimension of the network
k (int) : number of neighbours in grouping layer
channels (int) : number of planes/channels
'''
def __init__(self,
c_dim=128,
dim=3,
hidden_dim=128,
k = 40,
channels = 3):
super().__init__()
self.c_dim = c_dim
self.k = k #grouping layer
self.channels = channels
hidden_dim = 512
##Parameters are Tensor subclasses, that have a very special property when used
# with Module s - when they’re
# assigned as Module attributes they are automatically added
# to the list of its parameters, and will appear e.g. in parameters() iterator.
self.plane_weights = torch.nn.Parameter(torch.randn(channels, 4).cuda())
torch.nn.init.xavier_normal_(self.plane_weights)
# self.fc_pos = nn.Linear(dim, 2*hidden_dim)
self.plane_conv = convolution
self.mlp = MLP(channels = channels)
self.block_0 = ResnetBlockFC(2*hidden_dim, hidden_dim)
self.block_1 = ResnetBlockFC(2*hidden_dim, hidden_dim)
self.block_2 = ResnetBlockFC(2*hidden_dim, hidden_dim)
self.block_3 = ResnetBlockFC(2*hidden_dim, hidden_dim)
self.block_4 = ResnetBlockFC(2*hidden_dim, hidden_dim)
self.fc_c = nn.Linear(hidden_dim, c_dim)
self.actvn = nn.ReLU()
self.pool = maxpool
def forward(self, p):
batch_size, T, D = p.size()
# output size: B x T X F
# net = self.fc_pos(p)
# print(f'Weight planes {self.plane_weights}')
net_batch = []
for i in range(batch_size):
# print(f'Weight planes {self.plane_weights}')
net_sample = self.plane_conv(p[i,:,:], self.k, self.plane_weights, self.channels)
net_batch.append(net_sample)
# print(f'net_sample is {net_sample}')
# print(f'net_batch: {net_batch}')
net = torch.stack(net_batch)
net = self.mlp(net)
net = self.block_0(net)
pooled = self.pool(net, dim=1, keepdim=True).expand(net.size())
net = torch.cat([net, pooled], dim=2)
net = self.block_1(net)
pooled = self.pool(net, dim=1, keepdim=True).expand(net.size())
net = torch.cat([net, pooled], dim=2)
net = self.block_2(net)
pooled = self.pool(net, dim=1, keepdim=True).expand(net.size())
net = torch.cat([net, pooled], dim=2)
net = self.block_3(net)
pooled = self.pool(net, dim=1, keepdim=True).expand(net.size())
net = torch.cat([net, pooled], dim=2)
net = self.block_4(net)
# Recude to B x F
net = self.pool(net, dim=1)
c = self.fc_c(self.actvn(net))
return c
As you can see here, I added self.plane_weights as new parameters which will be used in plane_conv/convolution function.
But when I start training, I don’t see plane_weights being updated:
from im2mesh.encoder import point_plane_net
new_model = point_plane_net.PointPlaneResnet(k = 5).cuda()
#random input
input = torch.randn(10,10, 3).cuda()
labels = torch.randn(10,128).cuda() * 1000
input.size()
optimizer = optim.SGD(new_model.parameters(), lr=0.001, momentum=0.9)
optimizer.zero_grad()
criterion = nn.BCELoss()
for i in range(5):
a = list(new_model.parameters())[0]
print(a)
outputs = new_model(input)
outputs.shape
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
b = list(new_model.parameters())[0]
print(b)
print(torch.equal(a.data, b.data))
Can someone see from here if I am doing something wrong, shouldn’t autograd be responsible for updating the weights or should I maybe switch to different training loss?