I changed some part of the above code, in which the encoder take a whole tensor as input like below. In this case, are there any differences from above code in learning process?
class Encoder(nn.Module):
    def __init__(self):
        # ... layers to use

    def _forward(self, x):
        # x.shape: [b, c, h, w]
        x = F.relu(self.bn1(self.conv1(x)))
        x = F.relu(self.bn2(self.conv2(x)))
        x = F.relu(self.bn3(self.conv3(x)))
        x = F.relu(self.bn4(self.conv4(x)))
        return x

    def forward(self, x):
        # x.shape: [n, b, c, h, w]
        r = []
        for _ in x[:]:
            r.append(self._forward(_))
        return torch.stack(r)

...

for epoch in range(num_epochs):
    for images, labels in train_loader:
        # ...
        outs = encoder(images)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()