Ошибка обучения MLP с помощью Chainer

Я пытаюсь обучить и протестировать простой многослойный перцептрон, точно так же, как в первом руководстве по Chainer, но с моим собственным набором данных вместо MNIST. Это код, который я использую (в основном из учебника):

class MLP(Chain):
    def __init__(self, n_units, n_out):
        super(MLP, self).__init__()
        with self.init_scope():
            self.l1 = L.Linear(None, n_units)
            self.l2 = L.Linear(None, n_units)
            self.l3 = L.Linear(None, n_out)
    def __call__(self, x):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        y = self.l3(h2)
        return y

X, X_test, y, y_test, xHeaders, yHeaders = load_train_test_data('xHeuristicData.csv', 'yHeuristicData.csv')

print 'dataset shape   X:', X.shape, '  y:', y.shape

model = MLP(100, 1)
optimizer = optimizers.SGD()
optimizer.setup(model)

train = tuple_dataset.TupleDataset(X, y)
test = tuple_dataset.TupleDataset(X_test, y_test)

train_iter = iterators.SerialIterator(train, batch_size=100, shuffle=True)
test_iter = iterators.SerialIterator(test, batch_size=100, repeat=False, shuffle=False)
updater = training.StandardUpdater(train_iter, optimizer)
trainer = training.Trainer(updater, (10, 'epoch'), out='result')

trainer.extend(extensions.Evaluator(test_iter, model))
trainer.extend(extensions.LogReport())
trainer.extend(extensions.PrintReport(['epoch', 'main/accuracy', 'validation/main/accuracy']))
trainer.extend(extensions.ProgressBar())

trainer.run()

print 'Predicted value for a test example'
print model(X_test[0])

Вместо обучения и печати предсказанного значения я получаю следующую ошибку в «trainer.run ()»:

dataset shape   X: (1003, 116)   y: (1003,)
Exception in main training loop: __call__() takes exactly 2 arguments (3 given)
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/chainer/training/trainer.py", line 299, in run
    update()
  File "/usr/local/lib/python2.7/dist-packages/chainer/training/updater.py", line 223, in update
    self.update_core()
  File "/usr/local/lib/python2.7/dist-packages/chainer/training/updater.py", line 234, in update_core
    optimizer.update(loss_func, *in_arrays)
  File "/usr/local/lib/python2.7/dist-packages/chainer/optimizer.py", line 534, in update
    loss = lossfun(*args, **kwds)
Will finalize trainer extensions and updater before reraising the exception.
Traceback (most recent call last):
  File "trainHeuristicChainer.py", line 76, in <module>
    trainer.run()
  File "/usr/local/lib/python2.7/dist-packages/chainer/training/trainer.py", line 313, in run
    six.reraise(*sys.exc_info())
  File "/usr/local/lib/python2.7/dist-packages/chainer/training/trainer.py", line 299, in run
    update()
  File "/usr/local/lib/python2.7/dist-packages/chainer/training/updater.py", line 223, in update
    self.update_core()
  File "/usr/local/lib/python2.7/dist-packages/chainer/training/updater.py", line 234, in update_core
    optimizer.update(loss_func, *in_arrays)
  File "/usr/local/lib/python2.7/dist-packages/chainer/optimizer.py", line 534, in update
    loss = lossfun(*args, **kwds)
TypeError: __call__() takes exactly 2 arguments (3 given)

Я понятия не имею, как бороться с ошибкой. Я успешно обучал подобные сети с использованием других фреймворков, но меня интересует Chainer, потому что он совместим с PyPy.

Tgz-файл с файлами доступен здесь: https://mega.nz/#!wwsBiSwY!g72pC5ZgekeMiVr-UODJOqQfQZZU3lCqm9Er2jH4UD8


person ljmanso    schedule 01.12.2017    source источник


Ответы (1)


Вы отправляете кортеж (X, y) в MLP, в то время как реализованный __call__ принимает только x.

Вы можете изменить реализацию на

class MLP(Chain):
    def __init__(self, n_units, n_out):
        super(MLP, self).__init__()
        with self.init_scope():
            self.l1 = L.Linear(None, n_units)
            self.l2 = L.Linear(None, n_units)
            self.l3 = L.Linear(None, n_out)
    def __call__(self, x, y):
        h1 = F.relu(self.l1(x))
        h2 = F.relu(self.l2(h1))
        predict = self.l3(h2)
        loss = F.squared_error(predict, y)
        // or you can write it on your own as follows
        // loss = F.sum(F.square(predict - y))
        return loss

Он может отличаться по цепочке от других фреймворков, которые по умолчанию стандартное средство обновления принимает __call__ как функцию потерь. Таким образом, вызов model(X, y) вернет потерю текущего мини-пакета. Вот почему в учебном пособии по цепочке представлен еще один Classifier класс для вычисления функции потерь и упрощения MLP. Классификатор имеет смысл в MNIST, но не подходит для вашей задачи, поэтому вы можете самостоятельно реализовать функцию потерь.

Когда вы закончите обучение, вы можете просто сохранить экземпляр модели (возможно, добавив расширение snapshot_object в трейнер).

Чтобы использовать сохраненную модель, как при тестировании, вы должны написать другой метод в классе, который может быть назван как test, с такими же кодами, что и ваш текущий __call__, который имеет под рукой только X ввод и, следовательно, никаких других y не требуется.


Кроме того, если вы не хотите добавлять какие-либо дополнительные методы в класс MLP, делая его чистым, тогда вам нужно написать средство обновления самостоятельно и вычислить функцию потерь более естественным образом. Унаследовать стандартный проще, вы можете написать его так:

class MyUpdater(chainer.training.StandardUpdater):
    def __init__(self, data_iter, model, opt, device=-1):
        super(MyUpdater, self).__init__(data_iter, opt, device=device)
        self.mlp = model

    def update_core(self):
        batch = self.get_iterator('main').next()
        x, y = self.converter(batch, self.device)
        predict = self.mlp(x)
        loss = F.squared_error(predict, y)
        self.mlp.cleargrads()
        loss.backward()
        self.get_iterator('main').update()

updater = MyUpdater(train_iter, model, optimizer)
person Haruki Kirigaya    schedule 02.12.2017
comment
Хотя теперь у меня другая ошибка (в конечном итоге она предсказывает NaN, я разберусь с ней), ваше решение сработало. Спасибо! На всякий случай, если кто-то дойдет до этой страницы ... Для вычисления функции потерь мне пришлось использовать второй вариант: loss = F.sum (F.square (pred - y)) Первый вариант не удался за следующим исключением: File / usr /local/lib/python2.7/dist-packages/chainer/functions/loss/squared_error.py, строка 26, в обратном направлении g = gy [0] * 2 * self.diff TypeError: неподдерживаемые типы операндов для * : 'NoneType' и 'int' - person ljmanso; 05.12.2017