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权重资源地址