TL;博士,我的模型是为一个时代而训练的-为了测试目的。然而,当我对evaluate_generator方法进行多次评估时,每次运行相同的训练数据时,都会得到不同的精度。为什么会发生这种情况,在对同一模型的相同训练数据进行多次评估时,是否有办法获得相同的准确率?
我正在研究对话行为分类的语言问题,我的模型是基于这论文的。使用keras和keras_contrib存储库提供的工具,我正在复制精确的模型,但我有一个问题,为什么评估会给出不同的准确率。
作为参考,我将模型训练为一个时期,然后使用keras_contrib模块提供的实用工具keras_contrib将经过训练的模型保存在文件中。然而,每当我用这些权重来运行模型时,我就得到了不同的准确率,这是为一个时代而训练的。我试了5-10次,在68%到74%之间,这是相当大的。由于我是加载预先训练(即一个时代)的模型权重,我期待得到同样的准确性。(即浮点数的精度差)然而,以这个速度计算结果的差异表明我做了一些不正确的事情。
有谁知道为什么model.evaluate_generator方法产生的结果在每次我以相同的权重运行时都是如此不同,即使我使用相同的、经过1次训练的模型的权重来评估它呢?是否有任何方法来修正我的评估代码,以便在每次我进行评估时,相同的训练模型所获得的精度是相同的?(即因浮点运算而产生的细微差异)
下面是所有相关代码。与标准的StackOverflow问题相比,代码示例要长一些,但我想包含代码的所有相关部分。为代码的长度向Python程序员道歉。我是一个新手Python程序员,我可能会用一种更简洁,Python-惯用的方式来编写整个代码。
模型编制尾声:
def prepare_kadjk_model(max_mini_batch_size,
max_conversation_length, timesteps, num_word_dimensions,
word_to_index, word_vec_dict,
num_tags):
#Hyperparameters
m = timesteps
h = timesteps
model = Sequential()
dictionary_size = len(word_to_index) + 1
embedding_weights = numpy.zeros((dictionary_size, num_word_dimensions))
for word, index in word_to_index.items():
embedding_weights[index, :] = word_vec_dict[word]
# define inputs here
embedding_layer = Embedding(dictionary_size, num_word_dimensions,
weights=[embedding_weights],
embeddings_regularizer=regularizers.l2(0.0001))
model.add(TimeDistributed(embedding_layer,
input_shape=(max_conversation_length, timesteps)))
model.add(TimeDistributed(Bidirectional(LSTM(m // 2, return_sequences=True,
kernel_regularizer=regularizers.l2(0.0001)))))
model.add(TimeDistributed(Dropout(0.2)))
model.add(TimeDistributed(GlobalMaxPooling1D()))
model.add(Bidirectional(LSTM(h // 2, return_sequences = True,
kernel_regularizer=regularizers.l2(0.0001)), merge_mode='concat'))
model.add(Dropout(0.2))
crf = CRF(num_tags, sparse_target=False, kernel_regularizer=regularizers.l2(0.0001))
model.add(crf)
model.compile(optimizer, loss = crf_loss,
metrics=[crf_accuracy])
return model批次准备功能:
def form_mini_batches(dataset_x, max_mini_batch_size):
num_conversations = len(dataset_x)
# Form mini batches of equal-length conversations
mini_batches = {}
for i in range(num_conversations):
num_utterances = len(dataset_x[i])
if num_utterances in mini_batches:
mini_batches[num_utterances].append( i )
else:
mini_batches[num_utterances] = [ i ]
# Enforce max_batch_size on previously formed mini batches
mini_batch_list = []
for conversations in mini_batches.values():
mini_batch_list += [conversations[x: x + max_mini_batch_size] for x in range(0, len(conversations), max_mini_batch_size)]
return mini_batch_list
def kadjk_batch_generator(dataset_x, dataset_y, tag_indices,
mini_batch_list, max_conversation_length,
timesteps, num_word_dimensions, num_tags,
word_index_to_append, tag_index_to_append):
num_mini_batches = len(mini_batch_list)
# Shuffle the order of batches
index_list = [x for x in range(num_mini_batches)]
random.shuffle(index_list)
k = -1
while True:
k = (k + 1) % len(index_list)
index = index_list[k]
conversation_indices = mini_batch_list[index]
num_conversations = len(conversation_indices)
batch_features = numpy.empty(shape = (num_conversations, max_conversation_length, timesteps),
dtype = int)
label_list = []
for i in range(num_conversations):
utterances = dataset_x[conversation_indices[i]]
labels = copy.deepcopy(dataset_y[conversation_indices[i]])
num_utterances = len(utterances)
num_labels_to_append = max(0, max_conversation_length - len(labels))
labels += [tag_index_to_append] * num_labels_to_append
tags = to_categorical(labels, num_tags)
del labels
for j in range(num_utterances):
utterance = copy.deepcopy(utterances[j])
num_to_append = max(0, timesteps - len(utterance))
if num_to_append > 0:
appendage = [word_index_to_append] * num_to_append
utterance += appendage
batch_features[i][j] = utterance
del utterance
remaining_space = (max_conversation_length - num_utterances, timesteps)
batch_features[i][num_utterances:] = numpy.ones(remaining_space) * word_index_to_append
label_list.append(tags)
batch_labels = numpy.array(label_list)
del label_list
yield batch_features, batch_labels培训职能:
def train_kadjk(model, training, validation, num_epochs_to_train, tag_indices, max_mini_batch_size,
max_conversation_length, timesteps, num_word_dimensions, num_tags,
end_of_line_word_index, uninterpretable_label_index):
training_mini_batch_list = form_mini_batches(training[0], max_mini_batch_size)
validation_mini_batch_list = form_mini_batches(validation[0], max_mini_batch_size)
num_training_steps = len(training_mini_batch_list)
num_validation_steps = len(validation_mini_batch_list)
early_stop = EarlyStopping(patience = 5)
change_learning_rate = LearningRateScheduler(learning_rate_scheduler)
model.fit_generator(kadjk_batch_generator(training[0], training[1], tag_indices,
training_mini_batch_list, max_conversation_length,
timesteps, num_word_dimensions, num_tags,
end_of_line_word_index, uninterpretable_label_index),
steps_per_epoch = num_training_steps,
epochs = num_epochs_to_train,
validation_data = kadjk_batch_generator(validation[0], validation[1],
tag_indices,
validation_mini_batch_list,
max_conversation_length, timesteps,
num_word_dimensions, num_tags,
end_of_line_word_index,
uninterpretable_label_index),
validation_steps = num_validation_steps,
callbacks = [early_stop, change_learning_rate])评价职能:
def evaluate_kadjk(model, testing, tag_indices, max_mini_batch_size, max_conversation_length,
timesteps, num_word_dimensions, num_tags,
end_of_line_word_index, uninterpretable_label_index):
testing_mini_batch_list = form_mini_batches(testing[0], max_mini_batch_size)
num_testing_steps = len(testing_mini_batch_list)
score = model.evaluate_generator(kadjk_batch_generator(testing[0], testing[1],
tag_indices,
testing_mini_batch_list,
max_conversation_length, timesteps,
num_word_dimensions, num_tags,
end_of_line_word_index,
uninterpretable_label_index),
steps = num_testing_steps)
print("len(score):" + str(len(score)))
print("score:" + str(score))您可以浏览这里,以获得我正在研究的研究生论文项目的更全面的视角,但我试图为任何能够帮助您的人提供所有相关的功能片段。
发布于 2019-05-08 23:00:46
我深入研究了keras的Github问题,并在这评论中找到了错误的可能原因。
显然,与批处理规范化层类似,使用Dropout层会导致问题中所述的变化。在训练过程中,Dropout层减少了神经元的数量。因此,当模型的训练完成后,并不是所有的神经元都在最初编译的模型中出现。
如果使用函数keras_contrib.save_load_utils.save_all_weights保存模型权重,则保存模型的权重。但是,一旦您终止该过程而不保存最终的神经元配置(而不仅仅是权重),模型的最终配置就会丢失。正如前面提到的,这里是我用来保存模型的函数,save_all_weights不保存模型本身的配置。
因此,如果您在一个不同的过程中编译模型,并加载您使用keras_contrib.save_load_utils.load_all_weights保存的权重,即使您用与前一次运行测试模型相同的数据测试模型,新编译的模型也有一些额外的神经元在原始模型的培训过程中被删除。这种配置上的差异,再加上它们可能是(在这种情况下是用随机权重)初始化的事实,使评估在每次运行时都会给出不同的准确率。
解决方案似乎不仅记录权重,而且记录所有的配置。这可以简单地通过使用模型实例的save方法而不是keras_contrib.save_load_utils.save_all_weights来实现。显然,要将整个模型加载到不同的进程中,应该使用keras.models.load_model而不是keras_contrib.save_load_utils.load_all_weights。
发布于 2019-04-17 16:18:03
有各种各样的原因,这可能会发生,每一个下降的策略,在大多数DL模型随机化的某些方面的过程。大多数输入例程将包括一个shuffle操作,随机化输入集的顺序,作为平衡早期训练的一种方法。许多模型类型依赖于初始权值以某种方式被区分(允许对感知器进行区分训练),这通常是通过一些随机函数来完成的。
任何一种情况都会导致不同的训练结果,特别是早期训练。理想情况下,所有的训练跑将收敛到一个非常小的精确范围,但早期的结果将有所不同。这被认为不是一个问题。我们无法判断这是否是您的问题,因为您没有提供任何执行跟踪,例如转储所有初始权重或检查输入顺序。
如果您需要可重复的结果,那么您需要深入研究您的支持代码,确定使用RNG (随机数生成器)的地方,并做两件事中的一件:
在我的职业生涯中,我们通常都会随机设定种子,因为当我们不再是控制怪胎时,我们很容易评论出来。-)我们不得不多次挖掘代码,因为我们的代码的不同层有时会使用多个RNG;我们必须强制每个RNG的种子。在Python和大多数其他语言中,调用很简单,例如
random.seed(1) # Sets 1 as the initial seed for the RNG.https://stackoverflow.com/questions/55731245
复制相似问题