Плохой аргумент для функции theano, неправильное количество измерений

Я предсказываю 20 чисел для задач регрессии из VGG, используя лазанью и теано. Для примера сценария, который я написал, количество изображений равно 100. Я думаю, что делаю что-то глупое, но застрял.

Глядя в Интернете, для людей, которые используют nolearn, это можно исправить, указав regression=True, но я просто использую лазанью

So:

('X.shape', (100, 3, 224, 224))
('y.shape', (100, 20))

Вот точное сообщение об ошибке

Traceback (most recent call last):
  File "script_1.py", line 167, in <module>
    loss = train_batch()
  File "script_1.py", line 90, in train_batch
    return train_fn(X_tr[ix], y_tr[ix])
  File "/usr/local/lib/python2.7/dist-packages/Theano-0.8.0rc1-py2.7.egg/theano/compile/function_module.py", line 786, in __call__
    allow_downcast=s.allow_downcast)
  File "/usr/local/lib/python2.7/dist-packages/Theano-0.8.0rc1-py2.7.egg/theano/tensor/type.py", line 177, in filter
    data.shape))
TypeError: ('Bad input argument to theano function with name "script_1.py:159"  at index 1(0-based)', 'Wrong number of dimensions: expected 1, got 2 with shape (16, 20).')

Вот модель

def build_model():
    net = {}
    net['input'] = InputLayer((None, 3, 224, 224))
    net['conv1'] = ConvLayer(net['input'], num_filters=96, filter_size=7, stride=2, flip_filters=False)
     ...............
    net['drop7'] = DropoutLayer(net['fc7'], p=0.5)
    net['fc8'] = DenseLayer(net['drop7'], num_units=20, nonlinearity=None)
    return net

Генераторы:

def batches(iterable, N):
    chunk = []
    for item in iterable:
        chunk.append(item)
        if len(chunk) == N:
            yield chunk
            chunk = []
    if chunk:
        yield chunk
def train_batch():
    ix = range(len(y_tr))
    np.random.shuffle(ix)
    ix = ix[:BATCH_SIZE]
    return train_fn(X_tr[ix], y_tr[ix])

Соответствующий обучающий фрагмент

X_sym = T.tensor4()
y_sym = T.ivector()
output_layer = net['fc8']
prediction = lasagne.layers.get_output(output_layer, X_sym)
loss = lasagne.objectives.squared_error(prediction, y_sym)
loss = loss.mean()
acc = T.mean(T.eq(T.argmax(prediction, axis=1), y_sym), dtype=theano.config.floatX)
params = lasagne.layers.get_all_params(output_layer, trainable=True)
updates = lasagne.updates.nesterov_momentum(loss, params, learning_rate=0.0001, momentum=0.9)

train_fn = theano.function([X_sym, y_sym], loss, updates=updates)
val_fn = theano.function([X_sym, y_sym], [loss, acc])
pred_fn = theano.function([X_sym], prediction)

for epoch in range(5):
    for batch in range(25):
       loss = train_batch()
.....

person madratman    schedule 26.03.2016    source источник


Ответы (1)


Выходные данные вашего прогноза имеют форму (размер пакета, 20), но ваша переменная y_sym является типом ivector, поэтому, предположительно, это вектор длины пакета. Я не уверен, что именно это вызывает ошибку, но я не думаю, что вы можете вычислить квадрат ошибки для этих двух величин. Один матричный, другой векторный, их формы не совпадают?

Каковы ваши цели регрессии? Если вы прогнозируете 20 чисел для каждой точки данных, ваш y_sym, вероятно, должен быть матрицей, тогда вы можете вычислить квадрат ошибки.

Другая возможность состоит в том, чтобы изменить последний слой, чтобы нелинейность была сигмовидной. Таким образом, вы можете интерпретировать свою сверточную нейронную сеть как производящую вероятности с несколькими метками. Затем вы можете синтетически создать целевые переменные вероятности с несколькими метками для вашей регрессии. Одним из примеров является, скажем, точка данных x имеет несколько меток 0, 1, 10. Вы можете создать вектор длины 20, где 0, 1, 10 похожи на 1-a для некоторого маленького a, а другие записи являются небольшими положительными числами. .

Вы также можете переключить свою целевую функцию на двоичную перекрестную энтропию. В этом случае мы не выполняем регрессию. Тем не менее, наша сеть по-прежнему выводит матрицу оценки класса, а не вектор. Обычно это функция потерь, используемая при обнаружении присутствия K различных объектов на изображении (например, кошка, собака, человек, автомобиль, велосипед и т. д.), например. многоуровневая классификация. Если вы хотите попробовать этот маршрут, мы изменим наш последний слой следующим образом:

net['fc8'] = DenseLayer(net['drop7'], num_units=20, nonlinearity=sigmoid)

Теперь я буду интерпретировать свою сеть как вывод вероятностей; каждая вероятность будет представлять собой показатель достоверности того, считает ли наша сеть, что этот класс объектов находится на изображении.

Теперь у нас будет следующая функция потерь:

X_sym = T.tensor4()
y_sym = T.imatrix() 
output_layer = net['fc8']
probabilities = lasagne.layers.get_output(output_layer, X_sym)
loss = lasagne.objectives.binary_crossentropy(probabilities, y_sym)
loss = loss.mean()
... the rest of the update stuff...
train_fn = theano.function([X_sym, y_sym], loss, updates=updates)

Ключевое отличие здесь в том, что наша целевая переменная y_sym теперь является матрицей. Это должна быть матрица размера {0,1} (размер пакета, K), где 0 представляет объект, отсутствующий на изображении, а 1 представляет объект, присутствующий на изображении.

А для вычисления точности предсказания с несколькими метками обычно используется оценка F1. Здесь приведена ссылка на то, как вычислить F1-оценку с помощью scikit-learn. В этом случае наша функция проверки будет другой, она может выглядеть примерно так:

 from sklearn.metrics import f1_score
 probabilities_fn = theano.function([X_sym], probabilities)
 confidence_threshold = .5 
 predictions = np.where(probabilities_fn(X_sym) > confidence_threshold, 1, 0)  
 f1_score(y_true, predictions, average='micro')

Приведенный выше фрагмент кода возвращает оценки вероятности/достоверности из нашей сети и любую вероятность, превышающую наш параметр trust_threshold, здесь я выбираю 0,5, мы будем интерпретировать это как присутствующую метку класса.

person Indie AI    schedule 28.03.2016
comment
Спасибо! Я понял это прошлой ночью и перешел на вектор, но, похоже, сейчас я испортил точность. - person madratman; 28.03.2016
comment
Невозможно исправить. Помогите, пожалуйста, с правильным выражением точности (это классификация по сниперу, что не так)? Я думаю, что я балуюсь с осью.. - person madratman; 28.03.2016
comment
Что ты перешел на вектор? Если вы пытаетесь классифицировать изображения, которые могут иметь несколько объектов, скажем, всего K классов (кошка, собака, человек, велосипед, автомобиль и т. д.), для каждой точки данных вам необходимо вывести оценки класса K, поэтому выходные данные вашей модели должны быть матрица. Если вы хотите отслеживать точность, я не считаю, что argmax больше не подходит, поскольку это ограничит вас прогнозированием только 1 класса для каждого изображения. Вы можете использовать что-то вроде оценки F1, которая обычно используется для классификации изображений с несколькими метками. - person Indie AI; 29.03.2016
comment
Упс. Я имел в виду матрицу, то есть поменял y_sym на матрицу. Спасибо за обновление ответа. Я пытаюсь предсказать координаты x и y 10 ключевых точек. Поэтому мне нужна регрессия. Я не уверен, что парадигма нескольких классов - правильный путь. Что мне нужно исправить, так это точность вывода регрессии в моем фрагменте кода для этого. Как вы думаете, что должно быть хорошей мерой в этом случае? Может быть, мне также следует масштабировать свои метки? (как сделано здесь danielnouri.org/notes/2014/12/17/). - person madratman; 30.03.2016
comment
Или, может быть, вы правы. Помните комментарий regression=True + nolearn в начале моего вопроса? Эта stackoverflow.com/questions/32654026/ предполагает, что в случае регрессии = True сеть без обучения выводит вероятности каждого класса и вычисляет потери с квадратом ошибки в выходном векторе. ctrl+f регрессия здесь github.com/dnouri/nolearn/blob /master/nolearn/lasagne/base.py - person madratman; 30.03.2016
comment
Итак, я изменил acc на T.mean(T.eq(prediction, y_sym), dtype=theano.config.floatX), следуя этой строке github.com/dnouri/nolearn/blob/master/nolearn/lasagne/. Сначала он начинает тренироваться с нулевой точностью. (эпоха, потеря, акк) выглядит как (0, 0,083694695249984144, 0,0) (1, 0,082823878840396284, 0,0) (2, 0,080720447788113048, 0,0) (3, 0,08289594320874, 0,0) (3, 0,08289594320874, 0,0) , (x = x/ширина, y=y/высота), от 0 до 1, поскольку начало координат находится вверху слева (соглашение opencv) - person madratman; 30.03.2016
comment
Может быть, моя точность должна быть примерно такой: acc = T.mean(T.sum(T.sqr(prediction - y_sym), axis=1), axis=0, dtype=theano.config.floatX) Кроме того, пробовал nolearn, но это также дает нанс. Вот код gist.github.com/madratman/2c799f8023eeb7cb3910985b4d6f541b - person madratman; 30.03.2016