卷积神经网络不学习 EEG 数据

数据挖掘 机器学习 Python 神经网络 卷积神经网络 西阿诺
2021-09-24 12:19:41

我已经为 2 类脑电图分类问题训练了一个简单的 CNN(使用 Python + Lasagne),但是,网络似乎没有学习。损失不会随着时间的推移而下降,分类准确度不会因随机猜测而下降(50%):

训练曲线

问题

  1. 导致这种情况的代码有什么问题吗?
  2. 是否有更好(更正确?)的方法来处理 EEG 数据?

脑电图设置

数据是从完成总共 1044 项脑电图试验的参与者那里收集的。每个试验持续 2 秒(512 个时间样本),有 64 个 EEG 数据通道,并标记为 0/1。所有的试验都被改组了,以免在一组参与者上学习并在另一组参与者上进行测试。

目标是在获得原始 EEG 数据的 64x512 矩阵后预测试验的标签

原始输入数据(我不能在这里作为研究项目的一部分显示)具有以下形状 (1044, 1, 64, 512)

然后以 60/20/20% 创建训练/验证/测试拆分

有了这么小的数据集,我会认为过度拟合会是一个问题,但训练损失似乎并没有反映出这一点

代码

网络架构:

def build_cnn(input_var=None):
    l_in = InputLayer(shape=(None, 1, 64, 512), input_var=input_var)

    l_conv1 = Conv2DLayer(incoming = l_in, num_filters = 32, filter_size = (1, 3),
                        stride = 1, pad = 'same', W = lasagne.init.Normal(std = 0.02),
                        nonlinearity = lasagne.nonlinearities.rectify)

    l_pool1 = Pool2DLayer(incoming = l_conv1, pool_size = (1, 2), stride = (2, 2))

    l_fc = lasagne.layers.DenseLayer(
            lasagne.layers.dropout(l_pool1, p=.5),
            num_units=256,
            nonlinearity=lasagne.nonlinearities.rectify)

    l_out = lasagne.layers.DenseLayer(
            lasagne.layers.dropout(l_fc, p=.5),
            num_units=2,
            nonlinearity=lasagne.nonlinearities.softmax)

    return l_out

注意:我尝试添加更多的转换/池层,因为我认为网络不够深,无法学习类别,但是 1)这不会改变我上面提到的结果,2)我见过其他 EEG 分类代码,其中一个简单的1个conv层网络可以超越随机机会

创建小批量的助手:

def iterate_minibatches(inputs, targets, batchsize, shuffle=False):
    assert len(inputs) == len(targets)
    if shuffle:
        indices = np.arange(len(inputs))
        np.random.shuffle(indices)
    for start_idx in range(0, len(inputs) - batchsize + 1, batchsize):
        if shuffle:
            excerpt = indices[start_idx:start_idx + batchsize]
        else:
            excerpt = slice(start_idx, start_idx + batchsize)
        yield inputs[excerpt], targets[excerpt]

运行模型:

def main(model='cnn', batch_size=500, num_epochs=500):
    input_var = T.tensor4('inputs')
    target_var = T.ivector('targets')

    network = build_cnn(input_var)

    prediction = lasagne.layers.get_output(network)
    loss = lasagne.objectives.categorical_crossentropy(prediction, target_var)
    loss = loss.mean()

    train_acc = T.mean(T.eq(T.argmax(prediction, axis=1), target_var),
                      dtype=theano.config.floatX)

    params = lasagne.layers.get_all_params(network, trainable=True)

    updates = lasagne.updates.nesterov_momentum(loss, params, learning_rate=0.01)

    test_prediction = lasagne.layers.get_output(network, deterministic=True)
    test_loss = lasagne.objectives.categorical_crossentropy(test_prediction,
                                                            target_var)
    test_loss = test_loss.mean()

    test_acc = T.mean(T.eq(T.argmax(test_prediction, axis=1), target_var),
                      dtype=theano.config.floatX)

    train_fn = theano.function([input_var, target_var], [loss, train_acc], updates=updates)

    val_fn = theano.function([input_var, target_var], [test_loss, test_acc])

    print("Starting training...")

    for epoch in range(num_epochs):
        # full pass over the training data:
        train_err = 0
        train_acc = 0
        train_batches = 0
        start_time = time.time()
        for batch in iterate_minibatches(train_data, train_labels, batch_size, shuffle=True):
            inputs, targets = batch
            err, acc = train_fn(inputs, targets)
            train_err += err
            train_acc += acc
            train_batches += 1

        # full pass over the validation data:
        val_err = 0
        val_acc = 0
        val_batches = 0
        for batch in iterate_minibatches(val_data, val_labels, batch_size, shuffle=False):
            inputs, targets = batch
            err, acc = val_fn(inputs, targets)
            val_err += err
            val_acc += acc
            val_batches += 1

    # After training, compute the test predictions/error:
    test_err = 0
    test_acc = 0
    test_batches = 0
    for batch in iterate_minibatches(test_data, test_labels, batch_size, shuffle=False):
        inputs, targets = batch
        err, acc = val_fn(inputs, targets)
        test_err += err
        test_acc += acc
        test_batches += 1

# Run the model
main(batch_size=5, num_epochs=30)
3个回答

当我使用 TensorFlow 构建自动驾驶汽车时,我遇到了同样的问题。我的神经网络的训练误差永远反弹,并且从未收敛到最小值。作为一个健全的检查,我什至不能故意让我的模型过拟合,所以我知道肯定有问题。对我有用的是扩展我的输入。我的输入是 0 到 255 之间的像素颜色通道,因此我将所有值除以 255。从那时起,我的模型训练(和验证)错误达到预期的最小值并停止反弹。我很惊讶它有多大的不同。我不能保证它适用于您的情况,但绝对值得一试,因为它很容易实现。

您的设置可能无法正常工作的原因有很多。但是,一个很好的开始是尝试在整个数据集的一个非常小的子样本上过度拟合您的模型,以查看问题是否出在代码中。

1.您的输入层似乎关闭,第一个维度是通道,请尝试,数据格式正确:

l_in = InputLayer(shape=(None, 64, 512, 1 ), input_var=input_var)

更干净的方法是用 conv1dLayer 替换 conv2dlayer,这就是您要复制的内容。

2.没有正确的处理脑电图的方法。但人们也经常使用频谱图和特征提取