输入维度不匹配的二元交叉熵 Lasagne 和 Theano

4
我阅读了网上所有关于人们忘记将目标向量更改为矩阵的问题的帖子,并且在进行了此更改后仍然存在问题,因此决定在这里提问。下面提到了解决方法,但是新的问题也出现了,我非常感谢你的建议!
使用卷积网络设置和二元交叉熵与sigmoid激活函数时,我遇到了维数不匹配的问题,但是只有在验证/测试数据评估期间才会出现问题,而不是在训练数据期间。由于某种奇怪的原因,我的验证集向量中有一个维度被切换了,我不知道为什么。如上所述,训练正常进行。代码如下,感谢您的帮助(对于劫持该线程我很抱歉,但我没有理由创建一个新的线程),其中大部分代码来自lasagne教程示例。
解决方法和新问题:
1. 在valAcc定义中删除“axis = 1”可以帮助,但是验证准确性仍为零,而且无论我有多少节点、层数、过滤器等,测试分类始终返回相同的结果。即使更改训练集大小(我有大约每个类别350个样本,其图像尺寸为48x64灰度图像),也不会改变这种情况。所以似乎有些问题。
网络创建:
def build_cnn(imgSet, input_var=None):
# As a third model, we'll create a CNN of two convolution + pooling stages
# and a fully-connected hidden layer in front of the output layer.

# Input layer using shape information from training
network = lasagne.layers.InputLayer(shape=(None, \
    imgSet.shape[1], imgSet.shape[2], imgSet.shape[3]), input_var=input_var)
# This time we do not apply input dropout, as it tends to work less well
# for convolutional layers.

# Convolutional layer with 32 kernels of size 5x5. Strided and padded
# convolutions are supported as well; see the docstring.
network = lasagne.layers.Conv2DLayer(
        network, num_filters=32, filter_size=(5, 5),
        nonlinearity=lasagne.nonlinearities.rectify,
        W=lasagne.init.GlorotUniform())

# Max-pooling layer of factor 2 in both dimensions:
network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))

# Another convolution with 16 5x5 kernels, and another 2x2 pooling:
network = lasagne.layers.Conv2DLayer(
        network, num_filters=16, filter_size=(5, 5),
        nonlinearity=lasagne.nonlinearities.rectify)

network = lasagne.layers.MaxPool2DLayer(network, pool_size=(2, 2))

# A fully-connected layer of 64 units with 25% dropout on its inputs:
network = lasagne.layers.DenseLayer(
        lasagne.layers.dropout(network, p=.25),
        num_units=64,
        nonlinearity=lasagne.nonlinearities.rectify)

# And, finally, the 2-unit output layer with 50% dropout on its inputs:
network = lasagne.layers.DenseLayer(
        lasagne.layers.dropout(network, p=.5),
        num_units=1,
        nonlinearity=lasagne.nonlinearities.sigmoid)

return network

所有集合的目标矩阵都是按照以下方式创建的(以训练目标向量为例)。
 targetsTrain = np.vstack( (targetsTrain, [[targetClass], ]*numTr) );

...以及theano变量如下

inputVar = T.tensor4('inputs')
targetVar = T.imatrix('targets')
network = build_cnn(trainset, inputVar)
predictions = lasagne.layers.get_output(network)
loss = lasagne.objectives.binary_crossentropy(predictions, targetVar)
loss = loss.mean()
params = lasagne.layers.get_all_params(network, trainable=True)
updates = lasagne.updates.nesterov_momentum(loss, params, learning_rate=0.01, momentum=0.9)
valPrediction = lasagne.layers.get_output(network, deterministic=True)
valLoss = lasagne.objectives.binary_crossentropy(valPrediction, targetVar)
valLoss = valLoss.mean()
valAcc = T.mean(T.eq(T.argmax(valPrediction, axis=1), targetVar), dtype=theano.config.floatX)
train_fn = function([inputVar, targetVar], loss, updates=updates,  allow_input_downcast=True)
val_fn = function([inputVar, targetVar], [valLoss, valAcc])

最后,这里有两个循环:训练和测试。第一个循环没问题,第二个却抛出了错误,摘录如下:

# -- Neural network training itself -- #
numIts = 100
for itNr in range(0, numIts):
train_err = 0
train_batches = 0
for batch in iterate_minibatches(trainset.astype('float32'), targetsTrain.astype('int8'), len(trainset)//4, shuffle=True):
    inputs, targets = batch
    print (inputs.shape)
    print(targets.shape)        
    train_err += train_fn(inputs, targets)
    train_batches += 1

# And a full pass over the validation data:
val_err = 0
val_acc = 0
val_batches = 0

for batch in iterate_minibatches(valset.astype('float32'), targetsVal.astype('int8'), len(valset)//3, shuffle=False):
    [inputs, targets] = batch
    [err, acc] = val_fn(inputs, targets)
    val_err += err
    val_acc += acc
    val_batches += 1

错误(摘录)
Exception "unhandled ValueError"
Input dimension mis-match. (input[0].shape[1] = 52, input[1].shape[1] = 1)
Apply node that caused the error: Elemwise{eq,no_inplace}(DimShuffle{x,0}.0, targets)
Toposort index: 36
Inputs types: [TensorType(int64, row), TensorType(int32, matrix)]
Inputs shapes: [(1, 52), (52, 1)]
Inputs strides: [(416, 8), (4, 4)]
Inputs values: ['not shown', 'not shown']

再次感谢您的帮助!

1个回答

3
看起来错误出现在验证准确性的评估中。当您从计算中删除“axis=1”时,argmax适用于所有内容,仅返回一个数字。然后,广播步骤介入,并且这就是为什么您会看到整个集合的相同值的原因。但根据您发布的错误, “T.eq” 操作引发错误,因为它必须将52 x 1与1 x 52向量(theano / numpy的矩阵)进行比较。因此,我建议您尝试使用以下行替换该行:
    valAcc = T.mean(T.eq(T.argmax(valPrediction, axis=1), targetVar.T))

我希望这可以修复错误,但我自己还没有测试过。
编辑: 错误出现在调用argmax操作时。 通常,argmax用于确定哪个输出单元被激活最多。 然而,在您的设置中,您只有一个输出神经元,这意味着对所有输出神经元进行argmax将始终返回0(对于第一个arg)。
这就是为什么您会觉得您的网络总是给您输出0的原因。
通过替换:
    valAcc = T.mean(T.eq(T.argmax(valPrediction, axis=1), targetVar.T))

使用:

    binaryPrediction = valPrediction > .5
    valAcc = T.mean(T.eq(binaryPrediction, targetVar.T)

您应该能够获得期望的结果。

我只是不确定是否仍然需要转置。


如上所述,当axis=1时会出现维度不匹配的错误。一旦我将其删除,错误就消失了,但训练似乎并没有起作用。我还尝试了压平预测结果,但又出现了另一个维度错误。 - gilgamash
好的,使用转置是可以的。但是现在在每个步骤中,验证准确性从第一次到最后一次迭代始终没有改变... - gilgamash
你能发布一下网络输出的维度吗?你的输入似乎是一个形状为_batchsize_ x stacksize x row x _col_的tensor4,是这样吗? - romeasy
让我们在聊天中继续这个讨论。点击此处进入聊天室 - gilgamash
再次感谢romeasy提供的绝佳聊天帮助!已点赞! - gilgamash
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接