模型子类化subclassing
通常 CNN->BatchNorm->ReLU 写10遍
模型子类化可以缩短代码
class CNNBlock(layers.Layer):
def __init__(self, out_channels, kernel_size=3):
super(CNNBlock, self).__init__()
self.conv = layers.Conv2D(out_channels, kernel_size, padding='same')
self.bn = layers.BatchNormalization()
def call(self, input_tensor, training=False):
x = self.conv(input_tensor)
x = self.bn(x, training=training)
x = tf.nn.relu(x)
return x
model = keras.Sequential(
[
CNNBlock(32),
CNNBlock(64),
CNNBlock(128),
layers.Flatten(),
layers.Dense(10),
]
)
model.compile(
optimizer=keras.optimizers.Adam(),
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'],
)
model.fit(x_train, y_train, batch_size=64, epochs=3, verbose=2)
model.evaluate(x_test, y_test, batch_size=64, verbose=2)
并且顺序式api还可以方便修改shape用作调试
ResNet
一个较大的模型,我们甚至看不到里面的各层,模型内有多个块,块内有3个CNN层
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist
# import keras
physical_devices = tf.config.list_physical_devices('GPU')
tf.config.experimental.set_memory_growth(physical_devices[0], True)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(-1, 28, 28, 1).astype('float32') / 255.0
x_test = x_test.reshape(-1, 28, 28, 1).astype('float32') / 255.0
# CNN -> BatchNorm -> ReLU(common structure)
# x10 a lot of code, so write a class
class CNNBlock(layers.Layer):
def __init__(self, out_channels, kernel_size=3):
super(CNNBlock, self).__init__()
self.conv = layers.Conv2D(out_channels, kernel_size, padding='same')
self.bn = layers.BatchNormalization()
def call(self, input_tensor, training=False):
x = self.conv(input_tensor)
x = self.bn(x, training=training)
x = tf.nn.relu(x)
return x
# model = keras.Sequential(
# [
# CNNBlock(32),
# CNNBlock(64),
# CNNBlock(128),
# layers.Flatten(),
# layers.Dense(10),
# ]
# )
class ResBlock(layers.Layer):
def __init__(self, channels):
super(ResBlock, self).__init__()
self.cnn1 = CNNBlock(channels[0])
self.cnn2 = CNNBlock(channels[1])
self.cnn3 = CNNBlock(channels[2])
self.pooling = layers.MaxPooling2D()
self.identity_mapping = layers.Conv2D(channels[1],1,padding='same')
def call(self, input_tensor, training=False):
x = self.cnn1(input_tensor, training=training)
x = self.cnn2(x, training=training)
x = self.cnn3(
x + self.identity_mapping(input_tensor), training=training,
)
return self.pooling(x)
class ResNet_Like(keras.Model):
def __init__(self, num_classes=10):
super(ResNet_Like, self).__init__()
self.block1 = ResBlock([32, 32, 64])
self.block2 = ResBlock([128, 128, 256])
self.block3 = ResBlock([128, 256, 512])
self.pool = layers.GlobalAveragePooling2D()
self.classifier = layers.Dense(num_classes)
def call(self, input_tensor, training=False): # fit:True ; evaluate:False
x = self.block1(input_tensor, training=training)
x = self.block2(x, training=training)
x = self.block3(x, training=training)
x = self.pool(x)
return self.classifier(x)
def model(self):
x = keras.Input(shape=(28, 28, 1))
return keras.Model(inputs=[x], outputs=self.call(x))
model = ResNet_Like(num_classes=10)
model.compile(
optimizer=keras.optimizers.Adam(),
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'],
)
model.fit(x_train, y_train, batch_size=64, epochs=3, verbose=2)
print(model.model().summary())
model.evaluate(x_test, y_test, batch_size=64, verbose=2)
自定义层
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist
# import keras
physical_devices = tf.config.list_physical_devices('GPU')
tf.config.experimental.set_memory_growth(physical_devices[0], True)
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(-1, 28 * 28).astype('float32') / 255.0
x_test = x_test.reshape(-1, 28 * 28).astype('float32') / 255.0
class MyModel(keras.Model):
def __init__(self, num_classes=10):
super(MyModel, self).__init__()
self.dense1 = layers.Dense(64)
self.dense2 = layers.Dense(num_classes)
def call(self, input_tensor):
x = tf.nn.relu(self.dense1(input_tensor))
return self.dense2(x)
model = MyModel()
model.compile(
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer=keras.optimizers.Adam(),
metrics=['accuracy'],
)
model.fit(x_train, y_train, batch_size=32, epochs=2, verbose=2)
model.evaluate(x_test, y_test, batch_size=32, verbose=2)
重写Dense
class Dense(layers.Layer):
def __init__(self, units):
super(Dense, self).__init__()
self.units = units
def build(self, input_shape):
self.w = self.add_weight(
name='w',
shape=(input_shape[-1], self.units),
initializer='random_normal',
trainable=True,
)
self.b = self.add_weight(
name='b', shape=(self.units,), initializer='zeros', trainable=True,
)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
重写ReLU并且实例化
class MyReLU(layers.Layer):
def __init__(self):
super(MyReLU, self).__init__()
def call(self, x):
return tf.math.maximum(x, 0)
class MyModel(keras.Model):
def __init__(self, num_classes=10):
super(MyModel, self).__init__()
self.dense1 = Dense(64)
self.dense2 = Dense(num_classes)
self.relu = MyReLU()
# self.dense1 = layers.Dense(64)
# self.dense2 = layers.Dense(num_classes)
def call(self, input_tensor):
x = self.relu(self.dense1(input_tensor))
return self.dense2(x)
保存和加载模型
顺序API
# Sequential API
model1 = keras.Sequential(
[
layers.Dense(64, activation='relu'),
layers.Dense(10)
]
)
函数API
# functional API
inputs = keras.Input(784)
x = layers.Dense(64, activation='relu')(inputs)
outputs = layers.Dense(10)(x)
model2 = keras.Model(inputs=inputs, outputs=outputs)
子类化
# subclassing
class MyModel(keras.Model):
def __init__(self):
super(MyModel, self).__init__()
self.dense1 = layers.Dense(64,activation='relu')
self.dense2 = layers.Dense(10)
def call(self, input_tensor):
x = tf.nn.relu(self.dense1(input_tensor))
return self.dense2(x)
model3 = MyModel()
Save and Load
# Specify model build from the three API's
model = model1
model.load_weights('saved_model/')
model.compile(
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
optimizer=keras.optimizers.Adam(),
metrics=['accuracy'],
)
model.fit(x_train, y_train, batch_size=32, epochs=2, verbose=2)
model.evaluate(x_test, y_test, batch_size=32, verbose=2)
model.save_weights('saved_model/')
model = keras.models.load_model('complete_saved_model/')
model.fit(x_train, y_train, batch_size=32, epochs=2, verbose=2)
model.evaluate(x_test, y_test, batch_size=32, verbose=2)
# model.save_weights('saved_model/')
model.save('complete_saved_model/')