Keras:在新实验中重用训练过的权重

Posted

技术标签:

【中文标题】Keras:在新实验中重用训练过的权重【英文标题】:Keras: Re-use trained weights in a new experiment 【发布时间】:2019-06-27 11:38:32 【问题描述】:

我对 Keras 很陌生,所以对于任何愚蠢的错误,我提前道歉。我目前正在尝试在两个数据集之间尝试一些好的旧跨域迁移学习。我这里有一个在我生成的语音识别数据集上训练和执行的模型(代码在这个问题的底部,因为它很长)

如果我要训练一个新模型,比如在不同的数据集上使用 model_2,那么我会从权重的初始随机分布中获得基线。

我想知道,是否可以训练model_1和model_2,然后,这是我不知道该怎么做的一点;我可以从 model_1 中获取两个 256 和 128 个密集层(具有训练的权重)并将它们用作 model_3 的起点 - 这是数据集 2,初始权重分布来自 model_1?

所以,最后,我有以下几点:

    Model_1 从随机分布开始并在 数据集 1 上进行训练 Model_2 从随机分布开始并在 数据集 2 上进行训练 Model_3,它从在 Model_1 中训练的分布开始,并在 数据集 2 上进行训练。

我的问题是,我将如何执行上述第 3 步?我不想冻结权重,我只想从过去的实验中得到一个用于训练的初始分布

任何帮助将不胜感激。谢谢!如果我没有说清楚我要做什么,请道歉

我训练 Model_1 的代码如下:

import numpy
import pandas
from keras.models import Sequential
from keras.layers import Dense
from keras.callbacks import EarlyStopping
from keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import KFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
import matplotlib.pyplot as plt
from keras.utils import np_utils
from keras.layers.normalization import BatchNormalization

import time
start = time.clock()



# fix random seed for reproducibility
seed = 1
numpy.random.seed(seed)

# load dataset
dataframe = pandas.read_csv("voice.csv", header=None)
dataset = dataframe.values
# split into input (X) and output (Y) variables
numVars = len(dataframe.columns) - 1
numClasses  =  dataframe[numVars].nunique()
X = dataset[:,0:numVars].astype(float)
Y = dataset[:,numVars]


print("THERE ARE " + str(numVars) + " ATTRIBUTES")
print("THERE ARE " + str(numClasses) + " UNIQUE CLASSES")




# encode class values as integers
encoder = LabelEncoder()
encoder.fit(Y)
encoded_Y = encoder.transform(Y)

# convert integers to dummy variables (i.e. one hot encoded)
dummy_y = np_utils.to_categorical(encoded_Y)


calls = [EarlyStopping(monitor='acc', min_delta=0.0001, patience=100, verbose=2, mode='max', restore_best_weights=True)]

# define baseline model
def baseline_model():
    # create model

    model = Sequential()

    model.add(BatchNormalization())

    model.add(Dense(256, input_dim=numVars, activation='sigmoid'))

    model.add(Dense(128, activation='sigmoid'))

    model.add(Dense(numClasses, activation='softmax'))
    # Compile model
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    return model


estimator = KerasClassifier(build_fn=baseline_model, epochs=2000, batch_size=1000, verbose=1)
kfold = KFold(n_splits=10, shuffle=True, random_state=seed)
results = cross_val_score(estimator, X, dummy_y, cv=kfold, fit_params='callbacks':calls)
print("Baseline: %.2f%% (%.2f%%)" % (results.mean()*100, results.std()*100))
#your code here    
print (time.clock() - start)

PS:两个数据集之间的输入属性和输出都将相同,所有会改变的是属性值。我很好奇,如果两个数据集有不同数量的输出类,可以这样做吗?

【问题讨论】:

【参考方案1】:

简而言之,要从 Model_1 微调 Model_3,只需在 model.compile(...) 之后调用 model.load_weights('/path/to/model_1.h5', by_name=True)。当然,你必须先保存训练好的 Model_1。

如果我理解正确,您在两个数据集中具有相同数量的特征和类,因此您甚至不需要重新设计模型。如果您有不同的类集,那么您必须为 Model_1 和 Model_3 的最后一层赋予不同的名称:

model.add(Dense(numClasses, activation='softmax', name='some_unique_name'))

【讨论】:

谢谢,这很有用——我没想到它只是一行!如果输入不同且输出相同,您能否解释上述内容将如何工作?例如。在情感分析中 [pos, neu, neg] 类在两个域之间共享但输入不同?那么有没有办法加载隐藏层权重? 如果你在同一个领域工作(比如 NLP 或图像识别),特征大多保持不变,否则预训练的模型将无用。例如,大多数 NLP 任务都在固定大小的词嵌入上运行。从技术上讲,如果您在输入后使用密集层,则必须创建一个具有相同大小的新层并给它一个不同的名称。但从概念上讲,这没什么意义。

以上是关于Keras:在新实验中重用训练过的权重的主要内容,如果未能解决你的问题,请参考以下文章

预训练模型与Keras.applications.models权重资源地址

训练后使用量化权重进行 keras 模型评估

Keras - 获得训练层的权重

在 Keras 层中重置权重

如果我将层传递给两个 Keras 模型并且只训练一个模型,那么在前者训练后两个模型会共享权重吗

Tensorflow+keras使用keras API保存模型权重plot画loss损失函数保存训练loss值