# The size of tensor a must match the size of tensor at non-singleton dimension 2

Good day all,

I’m very sorry for constantly asking question. I’m actually a student and trying to learn how to use pytorch very well for my research in deep learning & signal processing. I have tried all possible ways to make the tensors’ dimensions compatible but couldn’t.

``````import os
import torch
import numpy as np

SNR_dB_min = 8
SNR_dB_max = 13
rho = 0.55
seed = 2
N = 60
K = 30
batch_size = 5000
Random_Channel = 'True'
dtype = torch.FloatTensor

def vec_multiplication(W, b):

#A = torch.mm(W, b.unsqueeze(2))
#C = A.unsqueeze(-1)
A = np.dot(W, np.expand_dims(b, 2)).astype(np.float32)
C = np.squeeze(A, axis = -1)
C = torch.from_numpy(C)
return C

class Modulator(object):

def __init__(self, mod_type, K):

# Create constellation
self.mod_type = mod_type
self.K = K

# Set modulation type
if (mod_type not in ['BPSK', '4PAM']):
raise(Exception('Modulator: Unknown modulation format'))
if (self.mod_type == 'BPSK'):
self.constellation = np.array([-1.0, 1.0])
self.constellation = (torch.from_numpy(self.constellation)).type(dtype)
elif (self.mod_type == '4PAM'):
self.constellation = np.array([-3.0, -1.0, 1.0, 3.0])
self.constellation = (torch.from_numpy(self.constellation)).type(dtype)

self.constellation_size = self.constellation.shape[0]

# Normalize constellation to unit power and convert to tensor
self.constellation /= torch.sqrt(torch.mean(torch.abs(self.constellation)**2))
#self.constellation = torch.Variable(self.constellation, requires_grad = False)
return

def random_indices(self, batch_size):
'''Generate random constellation symbol indices'''
indices = torch.FloatTensor(batch_size, self.K).uniform_(0, self.constellation_size).int()

return indices

def modulate(self, indices):
'''Map indices to constellation symbols'''

x = self.constellation[indices.long()]
return x

def gen_toeplitz_channel(self, N, rho):
'''Generate a random channel matrix with Toeplitz Gramian H'H
as done in the original paper
'''
HtH = np.zeros([self.K, self.K])
for i in range(self.K):
for j in range(self.K):
HtH[i,j] = rho ** np.abs(i-j)
T = np.random.normal(size=[N,N])
V, D, V = np.linalg.svd(HtH)
U = np.linalg.svd(np.dot(T,np.transpose(T)))
H = np.dot(np.dot(U[0][:,0:self.K],np.diagflat(np.sqrt(D))),V)
H = torch.from_numpy(H)
return H

def channel(self, x, N, snr_db_min, snr_db_max, rho, random_channel=False):
'''Simulate transmission over a random or static channel with SNRs draw uniformly
from the range [snr_db_min, snr_db_max]
'''
# Derive parameters from inputs
batch_size = x.shape[0]

# Channel matrices
if random_channel:
H = np.random.normal(0.0,1/np.sqrt(N), [batch_size, N, self.K]).astype(np.float32)
H = torch.from_numpy(H)
else:
H = (self.gen_toeplitz_channel(N, rho)).unsqueeze(0)
H = H.repeat([batch_size, 1, 1])

# Random noise
snr_db = torch.FloatTensor(batch_size, 1).uniform_(SNR_dB_min, SNR_dB_max).type(dtype)
w = torch.randn([batch_size, N]).type(dtype)
w = torch.mul(w, torch.pow(10.0, -snr_db/20.0))

# Channel output
y = vec_multiplication(H, x) + w
#y = torch.mm(torch.squeeze(H,-1), x) + w

return y, H

def demodulate(self, y):
'''Find closest constellation symbols in Tensor'''
shape = y.shape
y = y.reshape([-1, 1])
constellation = self.constellation.reshape([1, self.constellation_size])
indices = torch.argmin((torch.abs(y - constellation)), 1).type(dtype)
indices = indices.reshape(shape).long()
return indices

# Generate random transmit signals
mod = Modulator('BPSK', K)
indices = mod.random_indices(batch_size)
x = mod.modulate(indices)

# Send x through the channel
y, H = mod.channel(x, N, SNR_dB_min, SNR_dB_max, rho, random_channel='Random_Channel')

def zf(y, H):
'''Zero-Forcing Detector
Inputs:
y: Tensor of shape [batch_size, N]
H: Tensor of shape [batch_size, N, K]
mod: Instance of the modulator class
Outputs:
indices: Tensor of shape [batch_size, K]
'''
# Projected channel output
Hty = vec_multiplication(torch.transpose(H, 0, 2, 1), y)
#Hty = torch.mm(torch.transpose(H, 0, 2, 1), y)

# Gramian of transposed channel matrix
HtH = torch.mm(H, H.t())

# Inverse Gramian
HtHinv = torch.inverse(HtH)

# ZF Detector
x = vec_multiplication(HtHinv, Hty)
#x = torch.mm(HtHinv, Hty)

return x
``````

When the code is run, it returns the following error:

``````Traceback (most recent call last):
File "/Users/Abdullahi/Desktop/DETNET_INCOMPLETE/signal_modulation.py", line 120, in <module>
y, H = mod.channel(x, N, SNR_dB_min, SNR_dB_max, rho, random_channel='Random_Channel')
File "/Users/Abdullahi/Desktop/DETNET_INCOMPLETE/signal_modulation.py", line 100, in channel
y = vec_multiplication(H, x) + w
RuntimeError: The size of tensor a (5000) must match the size of tensor b (60) at non-singleton dimension 2
``````

Thank you very much.

1 Like

print out the shape of the tensors for all operations, and then you will get a better idea of how Tensor shapes change with each operation.
After that, you can figure out what line to change to make the dimensions match.

2 Likes

Thank you smth. I did exactly as you said. The problem is from the helper function for tensor multiplication:

``````def vec_multiplication(W, b):

#A = torch.mm(W, b.unsqueeze(2))
#C = A.unsqueeze(-1)
A = np.dot(W, np.expand_dims(b, 2)).astype(np.float32)
C = np.squeeze(A, axis = -1)
C = torch.from_numpy(C)
return C
``````

I later called this function to multiply two tensors:

``````    #Channel output
`y = vec_multiplication(H, x) + w`
``````

So, in an attempt to fix the bug, I commented the helper function, and instead of calling the helper function, I used the following function:

``````        y = torch.mm(H, x.unsqueeze(1))
y = y.squeeze(1) + w
``````

When the code is run, I have the following error:

``````    y, H = mod.channel(x, N, SNR_dB_min, SNR_dB_max, rho, random_channel='Random_Channel')
File "/Users/Abdullahi/Desktop/DETNET_INCOMPLETE/signal_modulation.py", line 101, in channel
y = torch.mm(H, x.unsqueeze(1))
RuntimeError: matrices expected, got 3D, 3D
``````

Thank you.

2 Likes