我不太喜欢通过super来 继承keras类。这里说的是通过功能函数实现的。
自定义激活函数
import os
from keras import backend as K
from keras.layers import Activation,Conv2D
from keras.utils.generic_utils import get_custom_objects
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
def swish(x):
'''
x:每个值
'''
return (K.sigmoid(x) * x)
get_custom_objects().update({'swish': Activation(swish)})
# 用法
net = Activation("swish")(net)
# 或者 都可以
net = (......,activation='swish')(net)
swish为自定义的激活函数,其中x为一个值,而不是tensor。
自定义层
import os
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
from keras.layer import Lambda,concatenate
from keras.backend import maximum,expand_dims
import keras.activations as activation
def MFM(net):
n = int(net.get_shape().as_list()[-1]/2)
tmp = []
for i in range(n):
tmp_value = maximum(net[...,i],net[...,-(i+1)])
tmp.append(expand_dims(tmp_value,axis=-1))
return concatenate(tmp,axis=-1)
...
...
net =Lambda(MFM,name='MFM')(net)
主要用到了Lambda这个函数。MFM是我定义的层函数。
自定义损失函数
这个不说了,直接放进去就行。
def mean_squared_error(y_true, y_pred):
return K.mean(K.square(y_pred - y_true), axis=-1)
...
...
model.compile(optimizer='rmsprop',loss=mean_squared_error)
其中必须有y_true和y_pred这两个参数,还可以有别的参数。但是要在他们后面。比如
from keras.layers import Input,Embedding,LSTM,Dense
from keras.models import Model
from keras import backend as K
word_size = 128
nb_features = 10000
nb_classes = 10
encode_size = 64
input = Input(shape=(None,))
embedded = Embedding(nb_features,word_size)(input)
encoder = LSTM(encode_size)(embedded)
predict = Dense(nb_classes, activation='softmax')(encoder)
def mycrossentropy(y_true, y_pred, e=0.1):
loss1 = K.categorical_crossentropy(y_true, y_pred)
loss2 = K.categorical_crossentropy(K.ones_like(y_pred)/nb_classes, y_pred)
return (1-e)*loss1 + e*loss2
model = Model(inputs=input, outputs=predict)
model.compile(optimizer='adam', loss=mycrossentropy)
y_true和y_pred这两个参数可以不用,比如说在定义triplet_loss的时候。
def _triplet_loss(self,y_true,y_pred):
anc,pos,neg = y_pred[:, 0:128], y_pred[:, 128:256], y_pred[:, 256:]
print('anc,pos,neg : ',anc.shape,pos.shape,neg.shape)
pos_dist = K.sum(K.square(anc-pos),axis=-1,keepdims=True)#,keepdims=True)
neg_dist = K.sum(K.square(anc-neg),axis=-1,keepdims=True)#,keepdims=True)
basic_loss = pos_dist-neg_dist+self.Margin
loss = K.maximum(basic_loss,0.0)
print("[INFO] model - triplet_loss shape: %s" % str(loss.shape))
return loss
自定义正则化器
任何输入一个权重矩阵、返回一个损失贡献张量的函数,都可以用作正则化器,例如:
from keras import backend as K
def l1_reg(weight_matrix):
return 0.01 * K.sum(K.abs(weight_matrix))
model.add(Dense(64, input_dim=64,
kernel_regularizer=l1_reg))
自定义初始化器
如果传递一个自定义的可调用函数,那么它必须使用参数 shape
(需要初始化的变量的尺寸)和 dtype
(数据类型)
from keras import backend as K
def my_init(shape, dtype=None):
return K.random_normal(shape, dtype=dtype)
model.add(Dense(64, kernel_initializer=my_init))
要是定义复杂初始化,那么就嵌套函数吧。比如conv+bn融合。
学习率
def lr_scheduler(epoch):
return learning_rate * (0.5 ** (epoch // lr_drop))
reduce_lr = keras.callbacks.LearningRateScheduler(lr_scheduler)
# 该回调函数是用于动态设置学习率
....
....
....
historytemp = model.fit_generator(datagen.flow(x_train, y_train,
batch_size=batch_size),
steps_per_epoch=x_train.shape[0] // batch_size,
epochs=maxepoches,
validation_data=(x_test, y_test), callbacks=[reduce_lr], verbose=2)