获得正确的张量大小

Get the right tensor size

我想要正确的张量大小,因为在 loss = criterion(out,target) 行中出现以下错误:

预期输入 batch_size (4200) 以匹配目标 batch_size (64)。

我该如何解决挑战?

我的输出张量具有大小 ([4200, 2]) 和我的目标张量 ([64,2])。 用例是图像 classification。有两个 class。我的批量大小是 64,图像的灰度大小为 180 x 115px。 请不要混淆:有一些 'break' 用于测试早期开发状态的代码。 我加载了四批,所以 256 张图像。

使用这种方法我将加载我的图像:

def dataPrep(list_of_data, data_path, category, quantity):
    global train_data
    target_list = []
    train_data_list = []
    
    transform = transforms.Compose([
    transforms.ToTensor(),
        ])
    
    len_data = len(train_data)
    print('Len_data: ', len_data)
    for item in list_of_data:
        f = random.choice(list_of_data)
        list_of_data.remove(f)
        print(data_path + f)
        try:
            img = Image.open(data_path +f)
        except:
            continue
        img_crop = img.crop((310,60,425,240))
        img_tensor = transform(img_crop)
        print(img_tensor.size())
        train_data_list.append(img_tensor)
        isPseudo = 0
        isTrue = 1
        if category == True:
            target = [isPseudo,isTrue]
        else:
            isPseudo =1
            isTrue = 0        
            target = [isPseudo, isTrue]
        
        target_list.append(target)
        if len(train_data_list) >=64:
            train_data.append((torch.stack(train_data_list), target_list))
            train_data_list = []
            target_list = []
            
        if (len_data*64 + quantity) <= len(train_data)*64:
            break
    print(len(train_data) *64)    
    return list_of_data

加载图像后,我创建模型和优化器。

model = net.Netz()
optimizer = optim.SGD(model.parameters(), lr= 0.1, momentum = 0.8)

我的 class 'Netz' 看起来像这样:

class Netz(nn.Module):
    def __init__(self):
        super(Netz, self).__init__()
        self.conv1 = nn.Conv2d(1,10, kernel_size=5)
        self.conv2 = nn.Conv2d(10,20, kernel_size = 5)
        self.conv_dropout = nn.Dropout2d() 
        self.fc1 = nn.Linear(320,60)
        self.fc2 = nn.Linear(60,2)
    
    def forward(self,x):
        x = self.conv1(x)
        x = F.max_pool2d(x, 2)
        x = F.relu(x)
        x = self.conv2(x)
        x = self.conv_dropout(x)
        x = F.max_pool2d(x,2)
        x = F.relu(x)
        x = x.view(-1,320)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, -1)

最后我会训练我的CNN:

def trainM(epoch):
    model.train()
    batch_id = 0
    for batch_id, (data, target) in enumerate(net.train_data):
        #data = data.cuda()
        #target = target.cuda()
        target = torch.Tensor(target[64*batch_id:64*(batch_id+1)])
        data = Variable(data)
        target = Variable(target)
        optimizer.zero_grad()
        out = model(data)
        criterion = F.nll_loss
        print('Size of out:', out.size())
        print('Size of target:', target.size())
        loss = criterion(out,target)
        loss.backward()
        optimizer.step()
        print('Tain Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(epoch,batch_id*len(data), len(net.train_data.dataset), 100*batch_id/len(net.train_data), loss.item()))
        batch_id += 1
        break

for item in range(0,10):
    trainM(item)
    break

据我所知,您需要一条线来分割数据,就像您在训练循环中对目标所做的那样:

target = torch.Tensor(target[64*batch_id:64*(batch_id+1)])
data   = torch.Tensor(data[64*batch_id:64*(batch_id+1)])

主要问题在 Netz x = x.view(-1,320) 你有 64 个批次 20 个通道 42 x 25 宽度和高度,如果你将它重塑为 -1,320 将得到 4200 x 320。

我可以建议 3 个可能的选项来保留批量大小;

  1. (一般的做法)将输入填充成正方形,更新卷积部分,使其在FC层之前的输出通道数多,高宽数少。例如获取 x.shape = (batchsize, 128,2,2) 然后获取 fc1 = Linear(512, 60) 并在此之前获取 x = x.reshape(x.shape[0], -1)。 (这里在应用 fc1 之前你可以做一个 1x1 卷积)。

  2. 使卷积结束时的通道数为 1,即得到类似 x.shape = (batchsize,1,42,25) 的内容,然后相应地采用 fc1

  3. dox=reshape(*x.shape[:2], -1) 换句话说,同时保留 chanel 和 batchsize。添加另一个 FC 层 fc_e = Linear(20,1) 以压缩您的频道。

class Netz(nn.Module):
    def __init__(self):
        super(Netz, self).__init__()
        self.conv1 = nn.Conv2d(1,10, kernel_size=5)
        self.conv2 = nn.Conv2d(10,20, kernel_size = 5)
        self.conv_dropout = nn.Dropout2d() 
        self.fc1 = nn.Linear(1050,60)
        self.fc2 = nn.Linear(60,2)
        self.fce = nn.Linear(20,1)
    
    def forward(self,x):
        x = self.conv1(x)
        x = F.max_pool2d(x, 2)
        x = F.relu(x)
        x = self.conv2(x)
        x = self.conv_dropout(x)
        x = F.max_pool2d(x,2)
        x = F.relu(x)
        x = x.reshape(x.shape[0],x.shape[1], -1)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        x = self.fce(x.permute(0,2,1)).squeeze(-1)
        return F.log_softmax(x, -1)

请记住,您需要在要表示的信息量(应该很高)和线性层的输入数量(不是那么高)之间进行权衡。最后,这取决于您选择如何解决该问题。第三个最接近你的解决方案,但我建议找出一个符合第一种方法的模型