Hi, there I will try to answer your questions here.
1: If you resize the image using transforms.Resize(244,244) all images will be of the size 244 so if the book says the input to the first layer is 256 it is wrong it will be [batch_size, 3,244, 244]
If you use the Kaggle dataset (I found out first hand) you should resize them so they are all the same size or you will get errors.
you can do this if you are not 100% sure about the shape of the tensor when running the code; in your Forward method do this
   def forward(self, x):
       print(x.shape)
        x = self.pool(torch.relu(self.conv1(x)))
        x = self.pool(torch.relu(self.conv2(x)))
        x = self.pool(torch.relu(self.conv3(x)))
        print(x.shape)
        # Flatten image
        x = x.view(x.size(0), -1)
        x = self.dropout(x)
        x = torch.relu(self.fc1(x))
        x = self.dropout(x)
        x = self.fc2(x)
        return x

So using the print(x.shape) will give you the tensors shape so you are 100% sure what is going in and out of the model.
For 2: This I think is called downsampling so you are making the data smaller by removing what is not ‘needed’ or ‘noise’ in the image.  I have seen them go both down and up in size in the FC layers.
3: For this what you should have in your dataset is two main folders a train and a validation folder. These two folders will then have both a cat and a dog folder.
So the structure would be like this
dataset/train/
…/cat/
… /dog/
dataset/valid/
…/cat/
… /dog/
Also, there should be no duplicate images in the folders. The code does not look like it is checking if the image exists or not. But you are right when thinking that the images should be moved rather than duplicated/copied. You do not want to have the same image in the train/valid/test folders as this will cause a sample bias in your dataset. So what you have looked ok but you will have to add the train path carefully like this
path = …/train/train/dog/
I hope that helps out a bit.