我正在尝试使用由 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% 的准确率。我怎样才能减少这个?
任何指针将不胜感激。
这是您的代码的修改,学习相对稳定。我改变了数据的生成方式,使其更具确定性,降低了 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 的 OUTPUT,您可以观察到准确率稳步增长并预测了不同的标签:
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]
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句