Реализация пакета для сегментации изображения

Я написал скрипт на 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()

Но для меня это выглядит так, будто шаг оптимизации (back-prop) применяется только к последнему изображению пакета. Это правда? И если так, как я могу это исправить? Я предполагаю, что, если я сделаю отступ в блоке with, то получу снова оптимизацию размера партии 1.

заранее спасибо

1 ответ

Решение

Но для меня это выглядит так, будто шаг оптимизации (back-prop) применяется только к последнему изображению пакета.

Это не должно применяться только на основе последнего изображения. Это должно применяться в зависимости от размера партии. Если вы установите bs=2 и это должно относиться к партии из двух изображений.

Шаг оптимизации фактически обновит параметры вашей сети. Backprop - это модное имя для системы автограда PyTorch, которая вычисляет градиенты первого порядка.

Другие вопросы по тегам