Keras保存最好的模型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Keras保存最好的模型相关的知识,希望对你有一定的参考价值。

参考技术A 比如Tensorboard是:

效果如下:

所有参数的设置:
参数

既然Tensorboard和ModelCheckpoint都属于keras.callbacks类,那我们把它们写到一起吧.

这样即保存了模型,也可以在tensorboard中可视化

再次使用模型的时候,需要调用

这个callbacks感觉很有用,
ReduceLROnPlateau

当评价指标不在提升时,减少学习率

当学习停滞时,减少2倍或10倍的学习率常常能获得较好的效果。该回调函数检测指标的情况,如果在patience个epoch中看不到模型性能提升,则减少学习率(是不是很棒!)

用示例学习 Keras

文章目录


但 CNN 的隐藏层大于或等于两层时,最好用 RELU 作为激活函数—— by zhuo 木鸟

网格寻优调参(包括网络层数、节点个数、编译方式等)

以神经网络+鸢尾花数据集为例:

from sklearn.datasets import load_iris
import numpy as np
from sklearn.metrics import make_scorer,f1_score,accuracy_score
from sklearn.linear_model import LogisticRegression
from keras.models import Sequential,model_from_json,model_from_yaml
from keras.layers import Dense
from keras.utils import to_categorical   # one-hot 咱不用
from keras.callbacks import ModelCheckpoint
from keras.wrappers.scikit_learn import KerasClassifier
# import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import KFold
from sklearn.preprocessing import LabelEncoder #导入LabelEncoder模块
le = LabelEncoder()   #实例一个LabelEncoder对象
X,y = load_iris(return_X_y=True)    #导入数据集
y = le.fit_transform(y)   #转换数据
span = list(set(y))    #将span赋值为test_df的取值范围(转换后)
le.inverse_transform(span)    #数据拟转换,可以查看各个数字的含义

seed = 7
np.random.seed(seed)

def create_ann(units_list=[10],optimizer='rmsprop',init='glorot_uniform'):
    ann = Sequential()
    units=units_list[0]
    ann.add(Dense(units=units,activation='relu',
                    input_shape=(4,),kernel_initializer=init))
    for units in units_list[1:]:
        ann.add(Dense(units=units,activation='relu',
                        kernel_initializer=init))
    ann.add(Dense(units=3,activation='sigmoid',kernel_initializer=init))
    ann.compile(loss='categorical_crossentropy',optimizer=optimizer)
    
    return ann

# ann = create_ann()
# ann.fit(X,y,batch_size=5,epochs=100,verbose=0)

model = KerasClassifier(build_fn=create_ann,epochs=100,batch_size=5,
                        verbose=0)    #可以看到,把 fit 的参数也带进去了。
# 但如果后文有用 grid 将其网格寻优,那么上面的设置其实可以不用的,只需要:
# model = KerasClassifier(build_fn=create_ann,verbose=0)
grid = 
grid['units_list']=[[10],[4,6],[3,4,3]]
grid['optimizer']=['rmsprop','adam']
grid['init']=['glorot_uniform','normal']
grid['epochs']=[50,25]
grid['batch_size']=[5,3]

kfold = KFold(n_splits=5,shuffle=True,random_state=seed)
scorer = make_scorer(f1_score,average='macro')  #用不了不知道为什么.......
# acc_scorer = make_scorer(accuracy_score)
grid_search = GridSearchCV(estimator=model,param_grid=grid,scoring=scorer,cv=kfold)
results = grid_search.fit(X,y)

print('Best:%f using %s'%(results.best_score_,results.best_params_))

means = results.cv_results_['mean_test_score']
stds = results.cv_results_['std_test_score']
params = results.cv_results_['params']
for mean,std,param in zip(means,stds,params):
    print('%f(+-%f) with: %r'%(mean,std,param))

模型筛选——交叉验证

假设有两个模型,一个是上面的神经网络,一个是逻辑回归。如何筛选最好的模型呢?

为了筛选模型,就要评价模型。评价模型的方法有交叉验证:

from sklearn.linear_model import LogisticRegression 
from sklearn.model_selection import cross_val_score
ann = KerasClassifier(build_fn=create_ann,epochs=100,batch_size=5,
                        units_list=[4,6],init='normal',
                        verbose=0)

lg = LogisticRegression(penalty='none')
S_lg_i = cross_val_score(lg,X,y,scoring=scorer,cv=kfold)    #计算出逻辑回归模型的Si
S_ann_i = cross_val_score(ann,X,y,scoring=scorer,cv=kfold)    #计算出ANN模型的Si
print('逻辑回归: Baseline:%.2f (+-%.2f) f1_score:',%(S_lg_i.mean(),S_lg_i.std()))
print('神经网络: Baseline:%.2f (+-%.2f) f1_score:',%(S_ann_i.mean(),S_ann_i.std()))

正则化 Dropout 与最大范数约束

from keras.layers import Dropout
from keras.constraints import maxnorm

def create_ann(optimizer='rmsprop',init='glorot_uniform'):
    ann = Sequential()
    ann.add(Dense(units=10,activation='relu',
                    input_shape=(4,),kernel_initializer=init))
    ann.add(Dropout(rate=0.2))
    ann.add(Dense(units=6,activation='relu',
                        kernel_initializer=init))
    ann.add(Dropout(rate=0.5))   #最好是 0.2~0.5 这个范围
    ann.add(Dense(units=6,activation='relu',
                        kernel_initializer=init,
                        kernel_constrain=maxnorm(3)))
    ann.add(Dense(units=3,activation='sigmoid',kernel_initializer=init))
    ann.compile(loss='categorical_crossentropy',optimizer=optimizer)
    
    return ann

学习率调整

线性衰减

衰减函数:
l r k = l r k + 1 × 1 1 + d e c a y × e p o c h s lr_k = lr_k+1\\times \\frac11+decay\\times epochs lrk=lrk+1×1+decay×epochs1

from keras.optimizers import SGD
learningRate = 0.1   #大学习率
momentum = 0.9   #大动量值 0.9~0.99
decay_rate = 0.005  
sgd = SGD(lr=learningRate,momentum=momentum,decay=decay_rate,nesterov=False)
model = KerasClassifier(build_fn=create_ann,epochs=100,batch_size=5,optimizer=sgd,
                        verbose=0)    

指数衰减

l r = l r × d r o p R a t e f l o o r ( 1 + e p o c h s e p o c h D r o p s ) lr = lr \\times dropRate^floor(\\frac1+epochsepochDrops) lr=lr×dropRatefloor(epochDrops1+epochs)

from keras.callbacks import LearningRateScheduler
from math import pow,floor
def step_decay(epoch):
	init_lrate = 0.1
	dropRate = 0.5
	epochDrops = 10
	lrate = init_lrate*pow(drop,floor(1+epoch)/epochDrops)
	return lrate
	
learningRate = 0.1   #大学习率
momentum = 0.9   #大动量值 0.9~0.99
decay_rate = 0
sgd = SGD(lr=learningRate,momentum=momentum,decay=decay_rate,nesterov=False)
lrate = LearningRateScheduler(step_decay)
model = KerasClassifier(build_fn=create_ann,epochs=100,batch_size=5,optimizer=sgd,
                        verbose=0,callbacks=[lrate])  

结果可视化

from sklearn.datasets import load_iris
import numpy as np
from sklearn.linear_model import LogisticRegression
X,y = load_iris(return_X_y=True)    #导入数据集
from keras.models import Sequential,model_from_json,model_from_yaml
from keras.layers import Dense
from keras.utils import to_categorical
from keras.callbacks import ModelCheckpoint
import matplotlib.pyplot as plt

y = to_categorical(y,num_classes=3)

seed = 7
np.random.seed(seed)

def create_model(optimizer='rmsprop',init='glorot_uniform'):
    model = Sequential()
    model.add(Dense(units=4,activation='relu',input_dim=4,kernel_initializer=init))
    model.add(Dense(units=6,activation='relu',kernel_initializer=init))
    model.add(Dense(units=3,activation='sigmoid',kernel_initializer=init))
    model.compile(loss='categorical_crossentropy',optimizer=optimizer,metrics=['acc'])
    
    return model

model = create_model()

filepath = 'weights-best.h5'
checkpoint = ModelCheckpoint(filepath=filepath,monitor='val_acc',
                              verbose=1,save_best_only=True,mode='max')
callback_list=[checkpoint]

history = model.fit(X,y,epochs=50,batch_size=5,verbose=0,callbacks=callback_list,validation_split=0.3)
print(history.history.keys())

font1 = 'family' : 'Times New Roman',
'weight' : 'normal',
'size'   : 20,

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False


plt.figure(figsize=(12,4))

plt.subplots_adjust(left=0.125, bottom=None, right=0.9, top=None,
                wspace=0.3, hspace=None)
plt.subplot(1,2,1)
plt.plot(history.history['loss'],linewidth=3,label='Train')
plt.plot(history.history['val_loss'],linewidth=3,linestyle='dashed',label='Test')
plt.xlabel('Epoch',fontsize=20)
plt.ylabel('loss',fontsize=20)
plt.legend(prop=font1)

plt.subplot(1,2,2)
plt.plot(history.history['acc'],linewidth=3,label='Train')
plt.plot(history.history['val_acc'],linewidth=3,linestyle='dashed',label='Test')
plt.xlabel('Epoch',fontsize=20)
plt.ylabel('Acc',fontsize=20)
plt.legend(prop=font1)

两种学习方法(重要)

1、从 create_model 函数中,直接建立:ann = create_model()。然后,在用 ann.fit。当然,在 fit 里面,要设置好 fit 的参数,如 validation_data,validation_split,epochs,batch_size,verbose 等等。

2、用 KerasClassifier 封装,ann = KerasClassifier(build_fn = create_model, arg*) 。这里的参数,不仅可以设置 fit 的参数,同时还可以设置 build_fn 的参数。不过,build_fn 的参数主要是编译时的参数,编译时的参数有:metrics,loss,optimizer。然后,metrics 不可以用 scorer 替代,只能用 keras 内置的 acc、mse 填进去。当然,build_fn 的参数可能还有 units_list,用来调整网络拓扑的、或者 rate,maxnorm,用来调整正则化参数。

模型文件管理

保存为 pickle 文件

pickle 不仅仅可以用于保存模型(包括权重),而且可以用来保存数据:

from sklearn.externals import joblib
joblib.dump(要保存的变量名,r'D:\\xxx\\xxx\\data.pkl')

载入 pickle 文件:

data = joblib.load(r'D:\\xxx\\xxx\\data.pkl')

当然,模型也可以用同样的方式,保存为 pickle 文件:

joblib.dump(要保存的模型变量,r'D:\\xxx\\xxx\\model.pkl')

保存为 HDF5 文件

注意,保存为 HDF5、JSON、YAML 只有 keras 才可以,sklearn 不可以

from keras.models import Sequential
from keras.layers import Dense,Activation    #导入神经层构造包
from keras.utils import to_categorical    #导入one-hot编码法
from sklearn.datasets import load_boston
from keras.models import load_model    
X,y = load_boston(return_X_y=True)
ANN = Sequential()    #定义一个sequential类,以便构造神经网络
ANN.add(Dense(units=64,activation=’relu’,input_shape=(len(X[1,:]),)))    
ANN.add(Dense(units=1,activation=’linear’))    #输出层,units即节点个数
ANN.compile(optimizer=’adam’,loss=’mse’)
#编译模型
ANN.fit(X,y,epochs=100,batch_size=50)
#对模型进行训练
ANN.save(‘model.h5’)    #保存模型为model.h5文件
model = load_model(“model.h5”)    #读取model.h5文件,并导入模型

保存为 JSON 与 YAML

from sklearn.datasets import load_iris
import numpy as np
from sklearn.linear_model import LogisticRegression
X,y = load_iris(return_X_y=True)    #导入数据集
from keras.models import Sequential,model_from_json,model_from_yaml
from keras.layers import Dense
from keras.utils import to_categorical

y = to_categorical(y,num_classes=3)

seed = 7
np.random.seed(seed)

def create_model(optimizer='rmsprop',init='glorot_uniform'):
    model = Sequential()
    model.add(Dense(units=4,activation='relu',input_dim=4,kernel_initializer=init))
    model.add(Dense(units=6,activation='relu',kernel_initializer=init))
    model.add(Dense(units=3,activation='sigmoid',kernel_initializer=init))
    model.compile(loss='categorical_crossentropy',optimizer=optimizer,metrics=['accuracy'])
    
    return model

model = create_model()
model.fit(X,y,epochs=50,batch_size=5,verbose=0)

model_json = model.to_json()
model_yaml = model.to_yaml()
with open('model.json','w') as file:
    file.write(model_json)
with open('model.yaml','w') as file:
    file.write(model_yaml)    
    
model.save_weights('model_weights.h5')

with open('model.json','r') as file:
    model_json_load = file.read()
with open('model.yaml','r') as file:
    model_yaml_load = file.read()
        
model_load1 = model_from_json(model_json_load)
model_load2 = model_from_yaml(model_yaml_load)
model_load1.load_weights('model_weights.h5')
model_load2.load_weights('model_weights.h5')

这里的保存模型,是将网络的拓扑结构保存为 JSON 或者 YAML。与保存为 HDF5 或者 Pickle 不同的是,它们保存的是模型的“形式”,而后者既保存了模型的拓扑、又同时保存了模型的参数。

当然,可以用 model.save_weights 的方式,将模型的参数单独保存为一个 HDF5 文件,然后再将网络的拓扑结构,保存为 JSON 或者 YAML 文件。

模型更新

一般的,为了保证模型的时效性,通常需要定期对模型进行更新。这个时间通常是 1~2 个月,或者 3-6 个月。更新的方法可以是全量更新、也可以是增量更新。

假设数据的增量为 X_increment,y_increment,那么增量更新可以直接是:

model.compile(loss='categorical_crossentropy',optimizer='rmsprop',metrics=['acc']
model.fit( X_increment,y_increment,epochs=10,batch_size=5,verbose=2)   #verbose 控制显示

也就是说,增量更新可以让我们重新编译模型(当然也可以不)。当然,全量更新是将新增的数据,加入

以上是关于Keras保存最好的模型的主要内容,如果未能解决你的问题,请参考以下文章

keras中保存自定义层和loss

keras 如何保存训练集与验证集正确率的差最小那次epoch的网络及权重

用示例学习 Keras

使用pytorch保存效果最好那个模型+加载模型

中文NLP笔记:13 用 Keras 实现一个简易聊天机器人

如何使用现有的和更新的类微调 keras 模型?