import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
class InvConv(nn.Module):
"""Invertible 1x1 Convolution for 2D inputs. Originally described in Glow
(https://arxiv.org/abs/1807.03039). Does not support LU-decomposed version.
Args:
num_channels (int): Number of channels in the input and output.
"""
def __init__(self, num_channels):
super(InvConv, self).__init__()
self.num_channels = num_channels
# Initialize with a random orthogonal matrix
#creat a random matrix
w_init = np.random.randn(num_channels, num_channels)
#w_init = q
w_init = np.linalg.qr(w_init)[0].astype(np.float32)
# turn array to tensor and turn it to a learnable parameter
self.weight = nn.Parameter(torch.from_numpy(w_init))
def forward(self, x, sldj, reverse=False):
ldj = torch.slogdet(self.weight)[1] * x.size(2) * x.size(3)
if reverse:
weight = torch.inverse(self.weight.double()).float()
sldj = sldj - ldj
else:
weight = self.weight
sldj = sldj + ldj
weight = weight.view(self.num_channels, self.num_channels, 1,1)
z = F.conv2d(x, weight)
return z, sldj
here is the original code
self.num_channel = 12
self.weight = torch([12,12])
weight is reshaped to tensor([12,12,1,1])
and x is the image size = tensor([64,12,16,16]) #(batch size,channels,H,W)
z = tensor([64,12,16,16])
the code is to use a 1X1 cone matrix ''self.weight'' to rearrange the input image x , the size of the kernel is 1x1 and have 12 channels (it has 12 kernels to formed a [12,12] self.weight) and because my model applies flow-based model , hence, I need to calculate the inverse of the convolution (reverse=True)
my problem is now I want to change the 1X1 kernel to a 2X2 kernel ,and the input and output shape is same as the above , hence I wrote my code as below
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
class InvConv(nn.Module):
"""Invertible 1x1 Convolution for 2D inputs. Originally described in Glow
(https://arxiv.org/abs/1807.03039). Does not support LU-decomposed version.
Args:
num_channels (int): Number of channels in the input and output.
"""
def __init__(self, num_channels):
super(InvConv, self).__init__()
self.num_channels = num_channels
# Initialize with a random orthogonal matrix
#creat a random matrix
w_init = np.random.randn(2*num_channels, 2*num_channels)
#w_init = q
w_init = np.linalg.qr(w_init)[0].astype(np.float32)
# turn array to tensor and turn it to a learnable parameter
self.weight = nn.Parameter(torch.from_numpy(w_init))
def forward(self, x, sldj, reverse=False):
ldj = torch.slogdet(self.weight)[1] * x.size(2) * x.size(3)
if reverse:
weight = torch.inverse(self.weight.double()).float()
sldj = sldj - ldj
else:
weight = self.weight
sldj = sldj + ldj
weight = weight.contiguous().view(self.num_channels, self.num_channels, 2,2)
z = F.conv2d(x, weight, stride=2, padding=x.size(2)//2)
return z, sldj
so now my self.weight is a tensor([24,24])
because I hope my output still remains at [64,12,16,16]
but I need my kernel size to be 2X2 , so the only way is to make self.weight larger
but if I use this code , my negative log-likelihood becomes negative , and the bits-per-dim is negative too , this is weird , and the bigger error is that the training will stop because of an error like the below
Traceback (most recent call last):
File "train.py", line 182, in <module>
main(parser.parse_args())
File "train.py", line 77, in main
train(epoch, net, trainloader, device, optimizer, scheduler,
File "/home/claire/miniconda3/envs/glow/lib/python3.8/site-packages/torch/autograd/grad_mode.py", line 27, in decorate_context
return func(*args, **kwargs)
File "train.py", line 95, in train
loss.backward()
File "/home/claire/miniconda3/envs/glow/lib/python3.8/site-packages/torch/_tensor.py", line 396, in backward
torch.autograd.backward(self, gradient, retain_graph, create_graph, inputs=inputs)
File "/home/claire/miniconda3/envs/glow/lib/python3.8/site-packages/torch/autograd/__init__.py", line 173, in backward
Variable._execution_engine.run_backward( # Calls into the C++ engine to run the backward pass
torch._C._LinAlgError: cusolver error: CUSOLVER_STATUS_EXECUTION_FAILED, when calling `cusolverDnSgesvd( handle, jobu, jobvt, m, n, A, lda, S, U, ldu, VT, ldvt, work, lwork, rwork, info)`. This error may appear if the input matrix contains NaN.