Масштабирование входных нейронных сетей - PullRequest
0 голосов
/ 27 апреля 2020

Я обучил простую полностью подключенную сеть на наборе данных CIFAR-10:

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(3*32*32, 300, bias=False)
        self.fc2 = nn.Linear(300, 10, bias=False)

    def forward(self, x):
        x = x.reshape(250, -1)
        self.x2 = F.relu(self.fc1(x))
        x = self.fc2(self.x2)
        return x


def train():
    # The output of torchvision datasets are PILImage images of range [0, 1].
    transform = transforms.Compose([transforms.ToTensor()])
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=250, shuffle=True, num_workers=4)
    testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
    testloader = torch.utils.data.DataLoader(testset, batch_size=args.bs, shuffle=False, num_workers=4)

    net = Net()
    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(net.parameters(), lr=0.02, momentum=0.9, weight_decay=0.0001)

    for epoch in range(20):
        correct = 0
        total = 0
        for data in trainloader:
            inputs, labels = data
            outputs = net(inputs)
            loss = criterion(outputs, labels)

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            _, predicted = torch.max(outputs.data, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
        acc = 100. * correct / total

Эта сеть достигает ~ 50% точности теста с заданными параметрами после 20 эпох. Обратите внимание, что я не делал никакого отбеливания входов (нет вычитания для каждого канала)

Затем я увеличил масштаб входов модели на 255, заменив outputs = net(inputs) на outputs = net(inputs*255). После этого изменения сеть больше не сходится. Я посмотрел на градиенты, и они, кажется, быстро растут после нескольких итераций, что приводит к тому, что все результаты модели равны нулю. Я хотел бы понять, почему это происходит.

Кроме того, я попытался уменьшить скорость обучения на 255. Это помогает, но сеть получает точность до ~ 43%. Опять же, я не понимаю, почему это помогает, и, что более важно, почему точность все еще ухудшается по сравнению с исходными настройками.

РЕДАКТИРОВАТЬ: забыл упомянуть, что я не использую смещения в этой сети.

EDIT2: я могу восстановить исходную точность, если уменьшу начальные веса в обоих слоях на 255 (в дополнение к уменьшению скорости обучения). Я также пытался уменьшить начальные веса только в первом слое, но в сети возникли проблемы с обучением (даже когда я уменьшил скорость обучения в обоих слоях). Затем я попытался уменьшить скорость обучения только на первом уровне - это тоже не помогло. Наконец, я попытался уменьшить скорость обучения в обоих слоях еще больше (на 255 * 255), и это неожиданно сработало. Это не имеет смысла для меня - уменьшение начальных весов на тот же коэффициент, что и масштабирование входов, должно полностью устранить любые отличия от исходной сети, вход на второй уровень идентичен. В этот момент скорость обучения должна быть уменьшена только в первом слое, но на практике оба уровня требуют значительно более низкой скорости обучения ...

Ответы [ 2 ]

0 голосов
/ 27 апреля 2020

Может быть, уменьшить скорость обучения на 1/255 ... просто предположение

0 голосов
/ 27 апреля 2020

Увеличение входных данных приведет к взрывным градиентам из-за нескольких наблюдений:

  1. Скорость обучения является общей для всех весов на данном этапе обновления.
  2. Следовательно, один и тот же коэффициент масштабирования (ie: скорость обучения) применяется к производной стоимости данного веса независимо от его величины, поэтому большие и малые веса обновляются по одной и той же шкале.
  3. Когда ландшафт потерь очень высок errati c, это приводит к взрывным градиентам (как эффект снежного кома, одно обновление с перерегулированием - скажем, ось одного конкретного веса - вызывает другое в противоположном направлении в следующем обновлении, которое снова выходит за пределы и т. д.)

Диапазон значений пикселей составляет от 0 до 255, следовательно, масштабирование данных на 255 обеспечит все входные данные от 0 до 1 и, следовательно, более плавную сходимость, поскольку все градиенты будут равномерными по отношению к скорости обучения. Но здесь вы масштабировали скорость обучения, которая корректирует некоторые из упомянутых выше проблем, но не так эффективна, как масштабирование самих данных. Это снижает скорость обучения и, следовательно, увеличивает время конвергенции, что может быть причиной того, что оно достигает 43% в 20 эпохах, может быть, ему нужно больше эпох ..

Кроме того: CIFAR-10 является значительным шагом вперед по сравнению с чем-то как и набор данных MNIST, следовательно, полностью подключенные нейронные сети не имеют мощности представления, необходимой для точного прогнозирования этих изображений. CNN - это способ go для любой задачи классификации изображений, кроме MNIST. Точность ~ 50% - это максимум, который вы можете получить с полностью подключенной нейронной сетью, к сожалению.

...