Keras C3DNN的预测结果相同

时间:2018-07-25 23:48:01

标签: neural-network keras classification

我正在尝试使用由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个时期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%的准确度。我该如何减少呢?

任何指针将不胜感激。

1 个答案:

答案 0 :(得分:1)

这是对代码的修改,可以相对稳定地学习。  我更改了数据的生成方式,使其更具确定性,减少了l2,辍学率和学习率,并增加了每个时期的步数。准确性开始稳步提高,超出了随机预测的预期范围。我认为您代码中的问题主要与x = np.array( ((label + 1) * 2) * np.random.randn(nframes, HEIGHT, WIDTH, NDIMS))仍然是高度随机的事实有关,即使其中包含有关标签的某些信息。同样,尺寸的急剧下降不是最佳的(您将102400的尺寸降低为1层的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个时期的输出,您可以在其中观察到精度不断提高并预测出不同标签的情况:

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]