这里先实现一个Lenet-5模型
input_data = keras.layers.Input(shape = (28,28,1))
conv_1 = keras.layers.Conv2D(filters=6, kernel_size=(5,5), strides=1, activation='relu', padding = 'same')(input_data)
pool_1 = keras.layers.AveragePooling2D(pool_size=(2,2), strides=2, padding='valid')(conv_1)
s1 = keras.layers.Normalization()(pool_1)
conv_2 = keras.layers.Conv2D(filters=16, kernel_size=(5,5),strides=1,activation='relu', padding = 'valid')(s1)
pool_2 = keras.layers.AveragePooling2D(pool_size=(2,2),strides=2, padding = 'valid')(conv_2)
s2 = keras.layers.Normalization()(pool_2)
conv_3 = keras.layers.Conv2D(filters=120, kernel_size = 5, strides=1, activation='relu', padding = 'valid')(s2)
flatten = keras.layers.Flatten()(conv_3)
dense = keras.layers.Dense(120, activation='relu')(flatten)
output = keras.layers.Dense(10, activation='softmax')(dense)
model = keras.Model(inputs = [input_data], outputs= [output])
checkPoint = ModelCheckpoint(filepath='model.h5', monitor='val_acc', verbose=1, save_best_only=True)
callback = [checkPoint]
model.compile(loss=’categorical_crossentropy', optimizer='sgd', metrics=['acc'])
hist = model.fit(x_train, y_train, batch_size=32, epochs=10, validation_split=0.3, callbacks=callback)
tensorflow构建模型有两种方法,一种是顺序式,一种是函数式,我用的是函数式。
神经网络架构:
输入 | 28,28,1 |
卷积层1 | 5,5,6 |
平均池化层1 | 2,2 |
卷积层2 | 5,5,16 |
平均池化层2 | 2,2 |
卷积层3 | 5,5,120 |
全连接层1 | 84 |
输出层 | 10 |
PS:中间隐藏层使用的是函数为tanh,末尾输出为softmax
我修改了激活函数,使用的是RELU,并在每一层输出后使用了归一化层.
依次为例,如果需要修改这个模型的组件,应该有哪些步骤呢?比如先修改一下损失函数,这里使用的是交叉熵。
修改为自己提供的损失函数。然后保存模型。应该怎么做?
先写出损失函数,考虑到批量梯度下降算法,应该是矩阵的算法
def My_loss(y_true, y_pred):
error = 0.5 * tf.square(y_true, y_pred)
return error
然后修改model.compile里面的loss参数
model.compile(loss=My_loss, optimizer='sgd', metrics=['acc'])
这样就能使用自己定义的组件了。
如果我想要修改0.5为0.1怎么办?
你可能会说,在函数里面修改一下不就得了嘛,但是我想保存模型的时候,把这个数字作为自定义的类型呢?
也就是当我们保存模型之后,再次加载模型,然后输入自己的参数。
每一个组件都有自己对应的父类,我们把自己的组件作为子类,然后继承父类,实现几个必要的函数就行了。然后使用字典进行初始化。这么说,肯定有点抽象,我们来做一件具体的事情
def My_loss(y_true, y_pred, r):
error = r * tf.square(y_true, y_pred)
return error
这里的r就是可变的,但是我们没办法使用到模型中,因为有三个参数,没办法灵活的定义r
model.compile(loss=My_loss(0.1), optimizer='sgd', metrics=['acc'])
你可能会想这么写
显然是错的,程序会崩溃。
解决办法是
def new_loss(r):
def My_loss(y_true, y_pred):
error = r * tf.square(y_true - y_pred)
return error
return My_loss
model.compile(loss=new_loss(0.1), optimizer='sgd', metrics=['acc'])
model.save_model('model.h5')
这样在保存的模型不会保存你之前设定的阈值,这里就必须自己设定了。
mymodel = keras.Models.load_model('model.h5', custum_objects={‘My_loss’:new_loss(0.1)})
如果想要保存下来,就必须用继承的方式
class NewLoss(keras.Losses.Loss):
def __init__(self,r, *kwargs):
self.r = r
super().__self__(*kwargs)
def call(self, y_true, y_y_pred):
def myloss(y_true, y_pred):
error = self.r * tf.square(y_true - y_pred)
return error
def get_config(self):
base_config = super().get_config()
return {**base_config, 'r' :self.r}
model = keras.models.load_model('model.h5', custom_objects={'NewLoss':NewLoss})
然后加载保存的模型 ,就不需要指定参数的大小
不仅仅是这样的损失函数可以保存,还可以自定义包括正则化,初始化,激活函数,层等等,方法与上面的损失一样。
3.建立自己的评价指标
??????? 评价指标有时候和损失函数混用,但是他们毕竟不是一个东西,我导师经常逼我用F1分数给神经网络调参,我真的好无语,如果我说损失函数必须可微才能执行梯度下降,她就会觉得我代码写错了,我最后只好说,啊对对对,我用的是f1分数调参。太痛了。总之,评价函数和损失函数是两个不一样的物种。
??????? keras.metrics里面有许多评价指标,精确度,召回率等等,在训练的时候,如果想要计算自己的指标,也可以按照上面提到的继承法来设置自己的指标。
class My_mertrics(keras.metrics.Metric):
def __init__(self, r =0.5, **kwargs):
super().__init__(**kwargs)
self.r = r
self.myloss = NewLoss(r)
self.total = self.add_weight('total', initializer='zeros')
self.count = self.add_weight('count', initializer='zeros')
def update_state(self, y_true, y_pred, sample_weight = None):
metric = self.myloss(y_true, y_pred)
self.total.assign_add(tf.reduce_sum(metric))
self.count.assign_add(tf.cast(tf.size(y_true), tf.float32))
def result(self):
return self.total / self.count
def get_config(self):
base_config = super().get_config()
return {**base_config, "r":self.r}
update_state是在每个训练批次进行调用的函数,keras会自动跟踪数据,最后每次返回前面所积累的数据 。
model.compile(loss=new_loss(0.1), optimizer='sgd', metrics=[My_metrics(0.1)])
就会输出自定义的标准了。