Возникли проблемы с обучением нейронной сети. Убыток не уменьшается - PullRequest
0 голосов
/ 09 января 2019

Я в основном слежу за этим проектом, но делаю пиксельную классификацию. У меня 8 классов и 9 изображений группы. Мои изображения сгруппированы в 9x128x128. Моя потеря не уменьшается, и точность тренировок не сильно колеблется. Я предполагаю, что у меня что-то не так с моделью. Любой совет высоко ценится! Я получаю точность не менее 91%, используя случайный лес.

Мои занятия крайне несбалансированы, поэтому я попытался откорректировать вес тренировок, исходя из доли классов в данных тренировок.

# get model
learning_rate = 0.0001
model = unet.UNetSmall(8)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# set up weights based on data proportion
weights = np.array([0.79594768, 0.07181202, 0.02347426, 0.0042031, 0.00366211, 0.00764327, 0.07003923, 0.02321833])
weights = (1 - weights)/7
print('Weights of training data based on proportion of the training labels.  Not compted here')
print(weights)
print(sum(weights))
criterion = nn.CrossEntropyLoss(weight = weight)
lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)

Вес данных обучения, основанный на пропорции меток обучения. Здесь не указано [0,02915033 0,13259828 0,13950368 0,1422567 0,14233398 0,14176525 0,13285154 0,13954024] 1,0000000000000002

Я нормализовал данные с помощью функции transforms.functional.normalize. Я рассчитал среднее значение и стандартное отклонение обучающих данных и добавил это увеличение в свой загрузчик данных.

dataset_train = data_utils.SatIn(data_path, 'TrainValTest.csv', 'train', transform=transforms.Compose([aug.ToTensorTarget(), aug.NormalizeTarget(mean=popmean, std=popstd)]))

Я увеличил свои тренировочные данные при предварительной обработке, поворачивая и переворачивая изображения. 1 сетка изображений затем стала 8.

Я проверил, что мои данные тренировок соответствуют моим классам, и все проверили. Поскольку я использую 8 классов, я решил использовать CrossEntropyLoss, так как в него встроен Softmax.

Текущая модель

class UNetSmall(nn.Module):
    """
    Main UNet architecture
    """
    def __init__(self, num_classes=1):
        super().__init__()
        # encoding
        self.conv1 = encoding_block(9, 32)
        self.maxpool1 = nn.MaxPool2d(kernel_size=2)
        self.conv2 = encoding_block(32, 64)
        self.maxpool2 = nn.MaxPool2d(kernel_size=2)
        self.conv3 = encoding_block(64, 128)
        self.maxpool3 = nn.MaxPool2d(kernel_size=2)
        self.conv4 = encoding_block(128, 256)
        self.maxpool4 = nn.MaxPool2d(kernel_size=2)

        # center
        self.center = encoding_block(256, 512)

        # decoding
        self.decode4 = decoding_block(512, 256)
        self.decode3 = decoding_block(256, 128)
        self.decode2 = decoding_block(128, 64)
        self.decode1 = decoding_block(64, 32)

        # final
        self.final = nn.Conv2d(32, num_classes, kernel_size=1)

    def forward(self, input):

        # encoding
        conv1 = self.conv1(input)
        maxpool1 = self.maxpool1(conv1)
        conv2 = self.conv2(maxpool1)
        maxpool2 = self.maxpool2(conv2)
        conv3 = self.conv3(maxpool2)
        maxpool3 = self.maxpool3(conv3)
        conv4 = self.conv4(maxpool3)
        maxpool4 = self.maxpool4(conv4)

        # center
        center = self.center(maxpool4)

        # decoding
        decode4 = self.decode4(conv4, center)
        decode3 = self.decode3(conv3, decode4)
        decode2 = self.decode2(conv2, decode3)
        decode1 = self.decode1(conv1, decode2)
        # final
        final = nn.functional.upsample(self.final(decode1), input.size()[2:], mode='bilinear')
        return final

Метод обучения

def train(train_loader, model, criterion, optimizer, scheduler, epoch_num):

    correct = 0
    totalcount = 0

    scheduler.step()

    # iterate over data
    for idx, data in enumerate(tqdm(train_loader, desc="training")):
        # get the inputs and wrap in Variable
        if torch.cuda.is_available():
            inputs = Variable(data['sat_img'].cuda())
            labels = Variable(data['map_img'].cuda())
        else:
            inputs = Variable(data['sat_img'])
            labels = Variable(data['map_img'])

        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels.long())
        loss.backward()
        optimizer.step()

        test = torch.max(outputs.data, 1)[1] == labels.long()
        correct += test.sum().item()
        totalcount += test.size()[0] * test.size()[1] * test.size()[2]

    print('Training Loss: {:.4f}, Accuracy: {:.2f}'.format(loss.data[0], correct/totalcount))
    return {'train_loss': loss.data[0], 'train_acc' : correct/totalcount}

Обучающий вызов в цикле эпохи

lr_scheduler.step()
train_metrics = train(train_dataloader, model, criterion, optimizer, lr_scheduler, epoch)

Некоторые итерации эпохи

#### Эпоха 0/19

---------- тренировка: 100% | ███████████████████████████████████████ ████████████████████████████████████████ | 84/84 [00:17 <00:00, 5.77it / s] Потеря тренировки: 0,8901, точность: 0,83 Текущее прошедшее время 2m 6s </p> #### эпоха 1/19

---------- тренировка: 100% | ██████████████████████████████████████ ████████████████████████████████████████ | 84/84 [00:17 <00:00, 5.72it / s] Потеря тренировки: 0,7922, точность: 0,83 Текущее прошедшее время 2м 24с </p> #### эпоха 2/19

---------- тренировка: 100% | ███████████████████████████████████████ ████████████████████████████████████████ | 84/84 [00:18 <00:00, 5.44it / s] Потеря тренировки: 0,8753, точность: 0,84 Текущее прошедшее время 2м 42с </p> #### эпоха 3/19

---------- тренировка: 100% | ██████████████████████████████████████ ████████████████████████████████████████ | 84/84 [00:18 <00:00, 5.53it / s] Потеря тренировки: 0,7741, Точность: 0,84 Текущее прошедшее время 3м 1с </p>

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Модель не соответствовала моим целям, и я не знаю достаточно о них, чтобы понять почему. Я переключился на другую найденную модель unet здесь и все начало работать.
Точность зависит от того, что производят случайные леса. Когда я пытался убрать вес, я получал НАН как потерю. С новым подходом потери снижаются до ~ 0,2 вместо зависания выше 0,5. Точность обучения довольно быстро возросла до высоких 80-х в первые 50 эпох и не превысила их в следующие 50.

Я планирую протестировать несколько разных моделей, похожих на то, что авторы сделали в этой статье. Я создам простую базу и сравню результаты с UNet и VGG16.

0 голосов
/ 11 января 2019

Трудно отладить вашу модель с помощью этой информации, но, возможно, некоторые из этих идей помогут вам в некотором роде:

  1. Попробуйте перегрузить вашу сеть гораздо меньшими данными и для многих эпох, не увеличивая сначала, скажем, одну-две партии для многих эпох. Если это не работает, то ваша модель не способна смоделировать связь между данными и желаемой целью, или у вас есть ошибка где-то. Более того, отладить его проще.
  2. Я не уверен насчет идеи весов, возможно, попробуйте повысить выборку недопредставленных классов, чтобы сделать их более сбалансированными (повторите несколько недопредставленных примеров в вашем наборе данных). Любопытно, откуда эта идея, никогда не слышал о ней.
  3. Вы пытались запустить модель из предоставленного вами репозитория, прежде чем применять собственные настройки? Насколько хорошо это работает, вы смогли повторить свои выводы? Как вы думаете, почему эта архитектура подойдет для вашего, как я понимаю, другого случая? Функция потери в указанной вами ссылке отличается, но архитектура та же. Я не читал эту статью и не пробовал вашу модель, но она кажется немного странной.
  4. Ссылка внутри репозитория GitHub указывает на сообщение в блоге, где рекомендуется использовать большие партии, поскольку это стабилизирует обучение, каков размер вашей партии?
  5. Может, начать с более мелкой и легкой модели и идти дальше?

И самое важное наступит последним; Я не думаю, что SO является лучшим местом для такого вопроса (особенно потому, что он ориентирован на исследования), я вижу, вы уже задавали его по вопросам GitHub, хотя, может быть, попытаться связаться с автором напрямую?

На вашем месте я бы начал с последнего пункта и с полного понимания операций и их влияния на вашу цель, удачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...