为图像分割实现批处理

Implementing Batch for Image Segmentation

我写了一个 Python 3.5 脚本来做街道分割。因为我是图像分割的新手,所以我没有使用 pytorch 中的预定义数据加载器,而是我自己编写了它们(为了更好地理解)。直到现在我只使用 1 的批量大小。现在我想将其概括为任意批量大小。

这是我的 Dataloader 的一个片段:

def augment_data(batch_size):


    # [...] defining some paths and data transformation (including ToTensor() function)

    # The images are named by numbers (Frame numbers), this allows me to find the correct label image for a given input image.
    all_input_image_paths = {int(elem.split('\')[-1].split('.')[0]) : elem for idx, elem in enumerate(glob.glob(input_dir + "*"))}
    all_label_image_paths = {int(elem.split('\')[-1].split('.')[0]) : elem for idx, elem in enumerate(glob.glob(label_dir + "*"))}


    dataloader = {"train":[], "val":[]}
    all_samples = []
    img_counter = 0

    for key, value in all_input_image_paths.items():
        input_img = Image.open(all_input_image_paths[key])
        label_img = Image.open(all_label_image_paths[key])

        # Here I use my own augmentation function which crops the input and label on the same position and do other things.
        # We get a list of new augmented data
        augmented_images = generate_augmented_images(input_img, label_img)
        for elem in augmented_images:
            input_as_tensor = data_transforms['norm'](elem[0])
            label_as_tensor = data_transforms['val'](elem[1])

            input_as_tensor.unsqueeze_(0)
            label_as_tensor.unsqueeze_(0)

            is_training_data = random.uniform(0.0, 1.0)
            if is_training_data <= 0.7:
                dataloader["train"].append([input_as_tensor, label_as_tensor])
            else:
                dataloader["val"].append([input_as_tensor, label_as_tensor])
            img_counter += 1

    shuffle(dataloader["train"])
    shuffle(dataloader["val"])
    dataloader_batched =  {"train":[], "val":[]}


    # Here I group my data to a given batch size
    for elem in dataloader["train"]:
        batch = []
        for i in range(batch_size):
            batch.append(elem)
        dataloader_batched["train"].append(batch)

    for elem in dataloader["val"]:
        batch = []
        for i in range(batch_size):
            batch.append(elem)
        dataloader_batched["val"].append(batch)

    return dataloader_batched

这是我的批量大小为 1 的训练方法的片段:

    while epoch <= num_epochs:
        # Each epoch has a training and validation phase
        for phase in ['train', 'val']:
            if phase == 'train':
                scheduler.step(3)
                model.train()  # Set model to training mode
            else:
                model.eval()  # Set model to evaluate mode

            running_loss = 0.0

            counter = 0
            # Iterate over data.
            for inputs, labels in dataloaders[phase]:
                counter += 1
                max_num = len(dataloaders[phase])

                inputs = inputs.to(device)
                labels = labels.to(device)

                # zero the parameter gradients
                optimizer.zero_grad()

                # forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    loss = criterion(outputs, labels)

                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                # statistics
                running_loss += loss.item() * inputs.size(0)


            epoch_loss = running_loss / dataset_sizes[phase]

如果我执行这个,我当然会得到错误:

for inputs, labels in dataloaders[phase]:
ValueError: not enough values to unpack (expected 2, got 1)

我明白为什么,因为现在我有一个图像列表,而不仅仅是像以前那样的输入和标签图像。所以我猜我需要第二个 for 循环来迭代这些批次。所以我尝试了这个:

            # Iterate over data.
            for elem in dataloaders[phase]:
                for inputs, labels in elem:
                    counter += 1
                    max_num = len(dataloaders[phase])

                    inputs = inputs.to(device)
                    labels = labels.to(device)

                    # zero the parameter gradients
                    optimizer.zero_grad()

                # forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    # _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)

                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

但对我来说,优化步骤(反向传播)似乎只应用于批次的最后一张图像。真的吗?如果是这样,我该如何解决?我想如果我缩进 with-Block,那么我将再次获得批量大小为 1 的优化。

提前致谢

But for me it looks like the optimization step (back-prop) is only applied on the last image of the batch.

它不应该只根据最后一张图片应用。它应该根据批量大小应用。 如果您设置 bs=2 并且它应该应用于两张图像的批次。

优化步骤实际上会更新您的网络参数。 Backprop 是计算一阶梯度的 PyTorch autograd 系统的奇特名称。