Error #1 when using tensor.view() in PyTorch

  • 2024/08/11
  • PyTorch view() Runtime error

About

I was trying to convert the model discussed in Building makemore Part 5: Building a WaveNet to use PyTorch APIs. I faced this error when trying to convert a tensor shape using view(). I sought Claude's help to resolve this.

Error

RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.

Before

class FlattenConsecutive(Module):  
    def __init__(self, n):  
        """  
        n - tells how many chars to concatenate in the last dimension of the tensor.
        
        Given a context of 8 chars: (1, 2, 3, 4, 5, 6, 7, 8)  
        if n = 2, then, the output will be:
            (1, 2), (3, 4), (5, 6), (7, 8)        
        """        
        super().__init__()  
        self.n = n  
  
    def forward(self, x):  
        # Batch size, Sequence length, no Channels  
        B, T, C = x.shape  
        x = x.view(B, T // self.n, C * self.n)  # Error is occurring here
		
		if x.shape[1] == 1:  
            x = x.squeeze(1)  
  
        return x

  • This error typically occurs when trying to reshape a tensor using view() when the tensor's memory is not contiguous. We can fix this by using reshape() instead, which is more flexible and can handle non-contiguous tensors.
  • The reshape() function is more flexible than view() and can handle tensors that are not contiguous in memory.

I asked: But, view() is faster as no memory needs to be copied, is it the same case with "reshape"?

view() operation:

  • Faster because it doesn't copy memory.
  • Works only on contiguous tensors.
  • Raises an error if the tensor is not contiguous.

reshape() operation:

  • More flexible as it works on both contiguous and non-contiguous tensors.
  • If the tensor is already contiguous, it behaves exactly like view() and doesn't copy memory.
  • If the tensor is not contiguous, it will make a copy of the tensor, which is slower.

After

  • Updated the module to use reshape() if the tensor data is stored in non-contiguous memory.
class FlattenConsecutive(Module):
    def __init__(self, n):
        """
        n - tells how many chars to concatenate in the last dimension of the tensor.
        
        Given a context of 8 chars: (1, 2, 3, 4, 5, 6, 7, 8)
        if n = 2, then, the output will be:
                (1, 2), (3, 4), (5, 6), (7, 8)
        """
        super().__init__()
        self.n = n

    def forward(self, x):
        # Batch size, Sequence length, no Channels
        B, T, C = x.shape

        if x.is_contiguous():
            x = x.view(B, T // self.n, C * self.n)
        else:
            x = x.reshape(B, T // self.n, C * self.n).contiguous()

        if x.shape[1] == 1:
            x = x.squeeze(1)

        return x