Keras 自定义模型:自定义fit的train_step

前言

接着《Tensorflow中的梯度和自动微分:tf.GradientTape理解》,开始自定义梯度,来解决无法定义类似于loss(y_pred, y_true) 的形式的损失函数问题。

本文参考了:
keras官方文档-The Model class
tf官方文档-Customize what happens in Model.fit

Keras创建Model类的两种方式

keras中创建模型有两种方式:

使用标准的 Functional API

import tensorflow as tf

inputs = tf.keras.Input(shape=(3,))
x = tf.keras.layers.Dense(4, activation=tf.nn.relu)(inputs)
outputs = tf.keras.layers.Dense(5, activation=tf.nn.softmax)(x)
model1 = tf.keras.Model(inputs=inputs, outputs=outputs)
model1.summary()

使用tf.keras.Model的子类

class MyModel(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.dense1 = tf.keras.layers.Dense(4, activation=tf.nn.relu)
        self.dense2 = tf.keras.layers.Dense(5, activation=tf.nn.softmax)
    def call(self, inputs):
        x = self.dense1(inputs)
        return self.dense2(x)

model2 = MyModel()

model1是类keras.engine.functional.Functional的实例,model2是自定义类MyModel的实例,但两者类别的父类都是tf.keras.Model。调用summary中可以看到,两者在在结构上是等价的:

>>> model1.summary()
Model: "model_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_2 (InputLayer)         [(None, 3)]               0         
_________________________________________________________________
dense_4 (Dense)              (None, 4)                 16        
_________________________________________________________________
dense_5 (Dense)              (None, 5)                 25        
=================================================================
Total params: 41
Trainable params: 41
Non-trainable params: 0
_________________________________________________________________
>>> model1.summary()
Model: "my_model_5"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_16 (Dense)             multiple                  16        
_________________________________________________________________
dense_17 (Dense)             multiple                  25        
=================================================================
Total params: 41
Trainable params: 41
Non-trainable params: 0
_________________________________________________________________

自定义Model.fit

先看一下fit的参数:

fit(x=None, y=None, batch_size=None,...)
x: 输入的数据
y: 数据标签(labels),如果x是tf.data.Dataset对象, 不需要传递y

实现train_step函数

官方文档中对该train_step的解释为:

实现一个train step的逻辑。可以重写这个方法来实现自定义的训练逻辑, 通常包含前向传播、损失计算、后向传播、度量更新。

创建train_step需要如下步骤:

  1. 创建GradientTape,通过前向传播记录loss相对于可训练变量的计算过程;
  2. 调用GradientTape.gradient计算loss相对于可训练变量的梯度;
  3. 使用优化器更新权重(需要传(gradient, variable) pairs.);
  4. 更新每次输出的metrics (包括跟踪loss的metrics)
  5. 返回一个将metrics名称映射到当前值的dict

模型

class CustomModel(keras.Model):
    def train_step(self, data):
        # Unpack dataset
        x, y = data
        # 1. 创建GradientTape,通过前向传播记录loss相对于可训练变量的计算过程;
        with tf.GradientTape() as tape:
            y_pred = self(x, training=True)
            loss = self.compiled_loss(y, y_pred, regularization_losses=self.losses)

        # 2. 计算梯度
        gradients = tape.gradient(loss, self.trainable_variables)
        # 3. 使用指定的优化器在模型上应用梯度
        self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))
        # 4. 更新每次输出的metrics.
        self.compiled_metrics.update_state(y, y_pred)
        # 5. 返回metrics, metricsm默认含有loss
        return {m.name: m.result() for m in self.metrics}

训练

import numpy as np

# Construct and compile an instance of CustomModel
inputs = keras.Input(shape=(32,))
outputs = keras.layers.Dense(1)(inputs)
model = CustomModel(inputs, outputs)
model.compile(optimizer="adam", loss="mse", metrics=["mae"])

# Just use `fit` as usual
x = np.random.random((1000, 32))
y = np.random.random((1000, 1))
model.fit(x, y, epochs=3)

输出:

import numpy as np

# 构建和配置CustomModel实例
inputs = keras.Input(shape=(32,))
outputs = keras.layers.Dense(1)(inputs)
model = CustomModel(inputs, outputs)
model.compile(optimizer="adam", loss="mse", metrics=["mae"])

# 训练
x = np.random.random((1000, 32))
y = np.random.random((1000, 1))
model.fit(x, y, epochs=3) 

针对代码的简单说明

  • 在执行model.compile前,model.optimizer为None,model.metrics为[];
  • compile定义了loss、optimizer和metrics,这是compile做的所有事(参考链接);
  • train_step函数是在调用model.fit 的时候执行的。

低阶API实现train_step






待更新…(2022-10-30)

import tensorflow as tf import numpy as np from keras import Model in_flow= np.load("X_in_30od.npy") out_flow= np.load("X_out_30od.npy") c1 = np.load("X_30od.npy") D1 = np.load("Y_30od.npy") print(c1.shape) print(D1.shape) max=np.max(out_flow) train_in_flow=in_flow[0:200]/max val_in_flow=in_flow[200:260]/max test_in_flow=out_flow[260:]/max train_out_flow=out_flow[0:200]/max val_out_flow=out_flow[200:260]/max test_out_flow=out_flow[260:]/max train_c1=c1[0:200]/max val_c1=c1[200:260]/max test_c1=c1[260:]/max train_D1=D1[0:200]/max val_D1=D1[200:260]/max test_D1=D1[260:]/max print(train_c1.shape, train_in_flow.shape, train_in_flow.shape, train_D1.shape) from keras.layers import * input_od=Input(shape=(5,109,109)) x1=Reshape((5,109,109,1),input_shape=(5,109,109))(input_od) x1=ConvLSTM2D(filters=64,kernel_size=(3,3),activation='relu',padding='same',input_shape=(5,109,109,1))(x1) x1=Dropout(0.2)(x1) x1=Dense(1)(x1) x1=Reshape((109,109))(x1) input_inflow=Input(shape=(5,109)) x2=Permute((2,1))(input_inflow) x2=LSTM(109,return_sequences=True,activation='sigmoid')(x2) x2=Dense(109,activation='sigmoid')(x2) x2=tf.multiply(x1,x2) x2=Dense(109,activation='sigmoid')(x2) input_inflow2=Input(shape=(5,109)) x3=Permute([2,1])(input_inflow2) x3=LSTM(109,return_sequences=True,activation='sigmoid')(x3) x3=Dense(109,activation='sigmoid')(x3) x3 = Reshape((109, 109))(x3) x3=tf.multiply(x1,x3) x3=Dense(109,activation='sigmoid')(x3) mix=Add()([x2,x3]) mix=Bidirectional(LSTM(109,return_sequences=True,activation='sigmoid'))(mix) mix=Dense(109,activation='sigmoid')(mix) model= Model(inputs=[input_od,input_inflow,input_inflow2],outputs=[mix]) model.compile(optimizer='adam', loss='mean_squared_error') history = model.fit([train_c1, train_in_flow,train_in_flow ],train_D1, validation_data=([val_c1,val_out_flow, val_in_flow], val_D1), epochs=100, batch_size=32) model.save("my_model.h10032") model.save_weights("my_model_weights.h10032") 根据上述程序利用保持好的模型预测并将预测结果可视化输出
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值