Expected 3-dimensional input for 3-dimensional weight [32, 100, 2], but got 2-dimensional input of size [32, 100] instead

username: kkdc
cooked: <p>I am planning to use CNN for a task of univariate time series forecasting. I am using the following settings for analysis, but I am having trouble with the error shown in the title.</p>
<pre><code class="lang-python">class TimeseriesDataset(torch.utils.data.Dataset):   
    def __init__(self, X, y, seq_len=1):
        self.X = X
        self.y = y
        self.seq_len = seq_len

    def __len__(self):
        return self.X.__len__() - (self.seq_len-1)

    def __getitem__(self, index):
        return (self.X[index:index+self.seq_len], self.y[index+self.seq_len])

class CNNForecast(nn.Module):
    def __init__(self, w, p_w):
        super(CNNForecast, self).__init__()
        self.first_conv1d = nn.Conv1d(in_channels=w, out_channels=32, kernel_size=2, stride=1, padding=0)
        self.maxpool1d = nn.MaxPool1d(kernel_size=2, stride=2)
        self.second_conv1d = nn.Conv1d(in_channels=50, out_channels=32, kernel_size=2, stride=1, padding=0)
        self.flatten = nn.Flatten()
        self.linear = nn.Linear(32*2, 40)
        self.dropout = nn.Dropout(p=0.5)
        self.out = nn.Linear(40, 1)

    def forward(self, x):
        x = F.relu(self.first_conv1d(x))
        x = self.maxpool1d(x)
        x = F.relu(self.second_conv1d(x))
        x = self.maxpool1d(x)
        x = self.flatten(x)
        x = self.dropout(x)
        x = self.out(x)
        return x

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = CNNForecast(w=100, p_w=1).to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=2e-5)
criterion = nn.L1Loss()

train_dataset = TimeseriesDataset(df['value'].values, df['value'].values, seq_len=100)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=False)

train_losses = []

model.train()
for epoch in range(30):
    epoch_loss = 0
    for batch, (inputs, labels) in enumerate(train_loader):
        inputs = inputs.to(device)
        labels = labels.to(device)
        print(inputs.size())
        print('-----')
        print(labels.size())
        optimizer.zero_grad()
        preds = model(inputs.float())
        loss = criterion(preds, labels)
        loss.backward()
        optimizer.step()
</code></pre>

username: eqy
cooked: <p>Something seems strange about the data loading vs. the weights here. If the weights to the first layer have 32 input channels <code>in_channels=w</code>, then the input should also have 32 channels. However, it looks like the 32 in the input is actually the “batch” dimension, with the channel dimension missing (as 100 is the sequence length dimension).</p>
<p>You can try reducing the number of input channels for the convolution to just 1, and reshaping the input to [32, 1, 100] in this case, or change the construction of the TimeseriesDataset so the input has two channels to match the first convolution layer.</p>
<p>You can read the details of the expected input and output shapes for a 1d convolution <a href="https://pytorch.org/docs/stable/generated/torch.nn.Conv1d.html#torch.nn.Conv1d" rel="noopener nofollow ugc">here</a>. Note that the input needs to be three dimensional, and match the number of input channels to the convolution.</p>

username: kkdc
cooked: <p>Thank you very much for your answer.<br>
If I follow your advice, should I do the following?</p>
<pre data-code-wrap="python"><code class="lang-python">inputs = inputs.reshape(32, 1, 100)
</code></pre>
<p>After adding the above process, I am facing another error.</p>
<blockquote>
<p>RuntimeError: Given groups=1, weight of size [32, 100, 2], expected input[32, 1, 100] to have 100 channels, but got 1 channels instead</p>
</blockquote>
<p>Where does the third element, 2, come from?</p>

username: eqy
cooked: <p>Right, for that to work, you must also change your <code>w</code> parameter to change the input channels from 100 to 1. With an input layout of <code>32, 1, 100</code>, the sequence <em>length</em> is 100, but the number of channels is 1.</p>
<p>The 2 comes from the <code>kernel_size</code> (e.g., the 1d convolution that is two time steps wide).</p>

username: kkdc
cooked: <p>Thank you for your reply.<br>
I followed your advice and modified the class as follows</p>
<pre data-code-wrap="python"><code class="lang-python">class CNNForecast(nn.Module):
    def __init__(self, w, p_w):
        super(CNNForecast, self).__init__()
        self.first_conv1d = nn.Conv1d(in_channels=1, out_channels=32, kernel_size=2, stride=1, padding=0)
        self.maxpool1d = nn.MaxPool1d(kernel_size=2, stride=2)
        self.second_conv1d = nn.Conv1d(in_channels=1, out_channels=32, kernel_size=2, stride=1, padding=0)
        self.flatten = nn.Flatten()
        self.linear = nn.Linear(32*2, 40)
        self.dropout = nn.Dropout(p=0.5)
        self.out = nn.Linear(40, 1)

    def forward(self, x):
        x = F.relu(self.first_conv1d(x))
        x = self.maxpool1d(x)
        x = F.relu(self.second_conv1d(x))
        x = self.maxpool1d(x)
        x = self.flatten(x)
        x = self.dropout(x)
        x = self.out(x)
        return x
</code></pre>
<p>I still face another problem below.</p>
<blockquote>
<p>RuntimeError: Given groups=1, weight of size [32, 1, 2], expected input[32, 32, 49] to have 1 channels, but got 32 channels instead</p>
</blockquote>
<p>What’s the problem?</p>

username: eqy
cooked: <p>The issue is that each layer’s input must be compatible with the previous layer’s output. For example, your first convolution has 32 output channels, but the second convolution expects just a single input channel. These numbers need to match.</p>

username: kkdc
cooked: <p>I’m sorry for asking so many times.<br>
I’ve changed the code as follows, but I’m facing another problem again.</p>
<pre data-code-wrap="python"><code class="lang-python">class CNNForecast(nn.Module):
    def __init__(self, w, p_w):
        super(CNNForecast, self).__init__()
        self.first_conv1d = nn.Conv1d(in_channels=1, out_channels=32, kernel_size=2, stride=1, padding=0)
        self.maxpool1d = nn.MaxPool1d(kernel_size=2, stride=2)
        self.second_conv1d = nn.Conv1d(in_channels=32, out_channels=32, kernel_size=2, stride=1, padding=0)
        self.flatten = nn.Flatten()
        self.linear = nn.Linear(32, 40)
        self.dropout = nn.Dropout(p=0.5)
        self.out = nn.Linear(40, 1)

    def forward(self, x):
        x = F.relu(self.first_conv1d(x))
        x = self.maxpool1d(x)
        x = F.relu(self.second_conv1d(x))
        x = self.maxpool1d(x)
        x = self.flatten(x)
        x = self.dropout(x)
        x = self.out(x)
        return x
</code></pre>
<blockquote>
<p>RuntimeError: mat1 dim 1 must match mat2 dim 0</p>
</blockquote>
<p>The input and output of each layer seems to correspond, but what is the problem?</p>

username: eqy
cooked: <p>It is a similar issue to before; the input shape to the first linear layer must be [?, 32] according to the current code. You can compute (or simply print the shape before the linear layer) to see what the shape of the linear layer should be changed to. However, I don’t see a call to the linear layer in your forward function so I’m not sure if the code posted corresponds to the error.</p>
<p>The <a href="https://pytorch.org/docs/stable/generated/torch.nn.Linear.html" rel="noopener nofollow ugc">docs for linear layer</a> show a good example of how the input shape should be matched to the linear layer.</p>

username: kkdc
cooked: <p>Thank you for your answer. I will check the output of each layer.</p>