【问题标题】:Keras C3DNN same result on predictionKeras C3DNN 预测结果相同
【发布时间】:2019-01-02 21:05:24
【问题描述】:

我正在尝试使用由 Tensorflow 支持的 Keras 中的 Conv3D 神经网络进行可变长度的多类序列分类。

我创建了一个小示例,在该示例中,我根据预期输出的标签生成输入分布。使用输入生成器训练网络后,预测结果始终是相同的值。

复制:

import numpy as np
import keras
from keras.utils import to_categorical
from keras.layers import Conv3D, Input, Flatten, Dense, Lambda, MaxPool3D, Dropout, Activation
from keras.regularizers import l2
from keras.optimizers import Adam
from random import randint
from keras.models import Model, Sequential
import keras.backend as K

#import os
#os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
HEIGHT = 40
WIDTH = 40
NDIMS = 1
NUM_CLASSES = 10

def get_data():
    nframes = randint(3,6)
    label = randint(0,NUM_CLASSES-1)
    x = np.array( ((label + 1) * 2)  * np.random.randn(nframes, HEIGHT, WIDTH, NDIMS))
    #print(np.std(x), label)
    x = np.expand_dims(x, axis=0)
    y = keras.utils.to_categorical([label], num_classes=NUM_CLASSES)
    return x,y

def input_generator():
    while True:
        x,y = get_data()
        yield (x, y)

def c3d():
    weight_decay = 0.005
    inputs = Input((None, HEIGHT, WIDTH, NDIMS))
    x = Conv3D(64,(3,3,3),strides=(1,1,1),padding='same',
            activation='relu',kernel_regularizer=l2(weight_decay))(inputs)
    x = MaxPool3D((2,2,1),strides=(2,2,1),padding='same')(x)
    x = Conv3D(128,(3,3,3),strides=(1,1,1),padding='same',
            activation='relu',kernel_regularizer=l2(weight_decay))(x)
    x = Lambda(lambda xa: K.sum(xa, axis=1))(x)
    x = Flatten()(x)
    x = Dense(64,activation='relu',kernel_regularizer=l2(weight_decay))(x)
    x = Dropout(0.5)(x)
    x = Dense(32,activation='relu',kernel_regularizer=l2(weight_decay))(x)
    x = Dropout(0.5)(x)
    x = Dense(NUM_CLASSES,kernel_regularizer=l2(weight_decay))(x)
    x = Activation('softmax')(x)

    lr = 0.005
    optimizer = Adam(lr=lr)
    model = Model(inputs, x)
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    return model

if __name__ == '__main__':
    model = c3d()
    model.fit_generator(input_generator(), samples_per_epoch=10, nb_epoch=50, verbose=1)
    values = []
    argmaxes = []
    for i in range(100):
        x,_ = get_data()
        val = model.predict(x)
        values.append(val)
        argmaxes.append(np.argmax(val))
    print(argmaxes)

对于最后一个打印语句,输出如下:

[ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, ... 

它在 (0, NUM_CLASSES-1) 范围内选择一个随机数,并将其用于每个预测。特征与其标签之间应该有一个模式。

更新:解决问题:

我已将问题简化为更基本的元素,但还不能在原始问题 (c3d) 中得到这些结果。我已经用重复的标签替换了特征数据,并且我能够让网络在一定程度上了解到重复 n 次的值实际上是分类。无论是可变长度还是非可变长度,从每 5 个 epoch 500 个样本的 3 次激活中观察最佳的最后 10 次平均准确度:

Input, activation, learning rate, layer size, activation, accuracy, sequence
np.repeat: tanh 0.001 48 adagrad 0.46319999999999995 False
np.repeat: sigmoid 0.001 64 adam 0.4720000000000001 False
np.repeat: relu 0.001 64 adam 0.30519999999999997 False

复制:

import numpy as np
import keras
from keras.utils import to_categorical
from keras.layers import Input, Dense, Lambda
from keras.optimizers import Adam, SGD, Adagrad, RMSprop
from random import randint
from keras.models import Model
import keras.backend as K

WIDTH = 40
NUM_CLASSES = 10
DIMENSIONS = 1
NO_SEQUENCE = False

def get_data():
    nframes = randint(3,6)
    label = randint(0,NUM_CLASSES-1)
    x = np.repeat(label, WIDTH * nframes).reshape(nframes, WIDTH).astype(np.float32)
    # x = np.array(((label + 1) * 2) * np.random.randn(nframes, WIDTH))
    if NO_SEQUENCE:
        x = x[0]
    # print(x, label)
    x = np.expand_dims(x, axis=0)
    y = keras.utils.to_categorical([label], num_classes=NUM_CLASSES)
    return x,y

def input_generator():
    while True:
        x,y = get_data()
        yield (x, y)

def cd(activation='relu', lr=0.0001, dense_size=16, optimizer=Adam()):
    if NO_SEQUENCE:
        inputs = Input((WIDTH,))
        x = Dense(dense_size, activation=activation)(inputs)
    else:
        inputs = Input((None, WIDTH))
        x = Dense(dense_size, activation=activation)(inputs)
        x = Lambda(lambda xa: K.sum(xa, axis=1))(x)
    x = Dense(NUM_CLASSES, activation='softmax')(x)
    optimizer.lr = lr
    model = Model(inputs, x)
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    return model

if __name__ == '__main__':
    activations = ['sigmoid', 'tanh', 'relu']
    learning_rates = [.01, .001, .0001, .00001]
    layer_sizes = [16, 32, 48, 64]
    optimizers = [('adagrad', Adagrad()), ('sgd', SGD()), ('rmsprop', RMSprop()), ('adam', Adam())]
    model = cd()
    print(model.summary())
    for a in activations:
        for lr in learning_rates:
            for ls in layer_sizes:
                for name, op in optimizers:
                    model = cd(a, lr, ls, op)
                    h = model.fit_generator(input_generator(), samples_per_epoch=500, nb_epoch=5, verbose=0)
                    print(a, lr, ls, name, np.average(h.history.get('acc')[-10:])) #average last 10 accuracies

问题:

为什么我的预测结果会这样?我该如何解决这个问题? 似乎增加训练量会产生更好的结果,但即使给定标签数组的输入,仍需要大量时间才能达到 50% 的准确度。我怎样才能减少这个?

任何指针将不胜感激。

【问题讨论】:

  • 可以分享一下训练进度吗?
  • 数据很多。今晚我会尝试发布它的要点。运行也需要一段时间。你有什么具体的要求吗?
  • 只是训练的演变(损失、指标等)。 fit 的输出

标签: neural-network keras classification


【解决方案1】:

这是对您的代码进行的修改,学习相对稳定。 我改变了数据的生成方式,使其更具确定性,降低了 l2、dropout 和学习率,并增加了每个 epoch 的步数。准确性开始稳步提高,超出随机预测的预期。我认为您的代码中的问题主要与 x = np.array( ((label + 1) * 2) * np.random.randn(nframes, HEIGHT, WIDTH, NDIMS)) 仍然高度随机这一事实有关,即使其中有一些关于标签的信息。此外,维数的急剧下降也不是最理想的(您在 1 层中从 102400 维变为 64 维),这需要相当多的批次才能让网络正确过滤噪声。此外,根据您对 x 的原始公式,不清楚哪个维度将包含有用信息,并且与高辍学率相结合,您肯定会在其他随机输入引入的大量噪声中丢失大量信息

代码:

import numpy as np
import keras
from keras.utils import to_categorical
from keras.layers import Conv3D, Input, Flatten, Dense, Lambda, MaxPool3D, Dropout, Activation
from keras.regularizers import l2
from keras.optimizers import Adam
from random import randint
from keras.models import Model, Sequential
import keras.backend as K

#import os
#os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
HEIGHT = 40
WIDTH = 40
NDIMS = 1
NUM_CLASSES = 10

def get_data():
    nframes = randint(3,6)
    label = randint(0,NUM_CLASSES-1)
    x = label++np.random.randn(nframes, HEIGHT, WIDTH, NDIMS)
    #print(np.std(x), label)
    x = np.expand_dims(x, axis=0)
    y = keras.utils.to_categorical([label], num_classes=NUM_CLASSES)
    return x,y

def input_generator():
    while True:
        x,y = get_data()
        yield (x, y)

def c3d():
    weight_decay = 0.000
    inputs = Input((None, HEIGHT, WIDTH, NDIMS))
    x = Conv3D(64,(3,3,3),strides=(1,1,1),padding='same',
            activation='relu',kernel_regularizer=l2(weight_decay))(inputs)
    x = MaxPool3D((2,2,1),strides=(2,2,1),padding='same')(x)
    x = Conv3D(128,(3,3,3),strides=(1,1,1),padding='same',
            activation='relu',kernel_regularizer=l2(weight_decay))(x)
    x = Lambda(lambda xa: K.sum(xa, axis=1))(x)
    x = Flatten()(x)
    x = Dense(64,activation='relu',kernel_regularizer=l2(weight_decay))(x)
    x = Dropout(0.0)(x)
    x = Dense(32,activation='relu',kernel_regularizer=l2(weight_decay))(x)
    x = Dropout(0.0)(x)
    x = Dense(NUM_CLASSES,kernel_regularizer=l2(weight_decay))(x)
    x = Activation('softmax')(x)

    lr = 0.0001
    optimizer = Adam(lr=lr)
    model = Model(inputs, x)
    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy'])
    return model

if __name__ == '__main__':
    model = c3d()
    print(model.summary())
    model.fit_generator(input_generator(), samples_per_epoch=1000, workers=5, use_multiprocessing=True, nb_epoch=5, verbose=1)
    values = []
    argmaxes = []
    for i in range(100):
        x,_ = get_data()
        val = model.predict(x)
        values.append(val)
        argmaxes.append(np.argmax(val))
    print(argmaxes)

前 5 个 epoch 的输出,您可以在其中观察到准确度稳步增长并预测不同的标签:

1000/1000 [==============================] - 216s 216ms/step - loss: 1.6944 - acc: 0.3840
Epoch 2/5
1000/1000 [==============================] - 222s 222ms/step - loss: 0.9882 - acc: 0.5920
Epoch 3/5
1000/1000 [==============================] - 225s 225ms/step - loss: 0.7479 - acc: 0.7050
Epoch 4/5
1000/1000 [==============================] - 221s 221ms/step - loss: 0.4670 - acc: 0.7950
Epoch 5/5
1000/1000 [==============================] - 214s 214ms/step - loss: 0.6742 - acc: 0.8040
[9, 5, 4, 8, 0, 7, 9, 2, 9, 1, 7, 7, 2, 5, 7, 2, 5, 2, 8, 5, 9, 9, 0, 3, 8, 1, 9, 7, 3, 9, 1, 0, 1, 4, 2, 0, 3, 5, 4, 4, 9, 7, 2, 2, 4, 2, 4, 6, 4, 0, 1, 6, 8, 4, 5, 9, 1, 1, 0, 2, 0, 4, 7, 0, 0, 4, 7, 3, 2, 2, 5, 6, 3, 6, 2, 4, 7, 1, 2, 7, 3, 6, 1, 3, 3, 0, 2, 8, 3, 2, 1, 2, 3, 7, 8, 7, 9, 9, 6, 6]

【讨论】:

  • 这是一个很好的答案,谢谢。我能够在本地重现这一点,我真的很喜欢你如何逐条列出我的模型中可能归因于其失败的特定点,并提供了一个如何提高准确性的示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-03
  • 2019-09-04
相关资源
最近更新 更多