keras建立网络的方法可以分为keras.models.Sequential() 和keras.models.Model()、继承类三种方式。
注意:tensorflow2.* 以后的版本可以直接使用tf.keras.Sequential()和tf.keras.Model()两个类。不用再使用keras.models的API
适用于简单线性堆叠网络。
流程:创建Sequential()对象,逐层堆叠网络
import tensorflow as tf
from tensorflow.keras import layers, models
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()
也可以不使用.add方法。直接在Sequntial里放入层列表
import tensorflow as tf
from tensorflow.keras import layers, models
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
layers.Conv2D(64, (3, 3), activation='relu'),
layers.Flatten(),
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')
])
model.summary()
注意:input_shape=(32, 32, 3),在模型搭建过程中会自动填空Batch维度,即None。而不需要在定义input_shape的时候进行定义。
第一列中的层名是按照层的类型默认1开始的序列后缀命名。
如果我们像实现一些更为复杂的网络,比如多输入多输出的模型就需要使用到keras.models.Model()来构建网络。如下代码同时输出最后卷积层Flatten后提取的特征层,以及分类结构。
流程使用keras.Input定义输入张量shape, 创建网络层;定义每层的输入和输出张量;keras.models.Model确定输入张量和输出层,keras可以根据每一层的输入输出关系完成整个网络图的创建。
import tensorflow as tf
from tensorflow.keras import layers, models, Input
input_tensor = Input(shape=(32, 32, 3))
x = layers.Conv2D(32, (3, 3), activation='relu')(input_tensor)
x = layers.MaxPooling2D((2, 2))(x)
x = layers.Conv2D(64, (3, 3), activation='relu')(x)
x = layers.MaxPooling2D((2, 2))(x)
x = layers.Conv2D(64, (3, 3), activation='relu')(x)
output_tensor1=layers.Flatten()(x)
x = layers.Dense(64, activation='relu')(output_tensor1)
output_tensor2 = layers.Dense(10, activation='softmax')(x)
model = models.Model(inputs=input_tensor, outputs=[output_tensor1, output_tensor2])
model.summary()
第一层卷积核参数:896=((3x3)x3+1)x32
第二层卷积核参数:18496=((3x3)x32+1)x64
第三个卷积核参数:36928=((3x3)x64+1)x64
(卷积核面积x上一层层数+1)x下一层层数
加1表示bias
第一个全连接层参数:1024x(64+1)=65600
第二个全连接层参数:10x(64+1)=650
(上一层层数+1)x下一层层数
在应对复杂结构的网络的时候,往往会按照采用自定义类(继承keras.models.Model)的方式来建立网络,使得整个网络结构更加规范整洁,同时通过call函数可以方便地处理复杂网络的输入输出关系。(有跟torch搭建思想借鉴的嫌疑)
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Model
class MyNet(Model):
def __init__(self):
super(MyNet, self).__init__()
self.conv1 = layers.Conv2D(32, (3, 3), activation='relu')
self.pool1 = layers.MaxPooling2D((2, 2))
self.conv2 = layers.Conv2D(64, (3, 3), activation='relu')
self.pool2 = layers.MaxPooling2D((2, 2))
self.conv3 = layers.Conv2D(64, (3, 3), activation='relu')
self.flatten = layers.Flatten()
self.fc1 = layers.Dense(64, activation='relu')
self.fc2 = layers.Dense(10, activation='softmax')
def call(self, inputs):
out = self.conv1(inputs)
out = self.pool1(out)
out = self.conv2(out)
out = self.pool2(out)
out = self.conv3(out)
out = self.flatten(out)
out = self.fc1(out)
out = self.fc2(out)
return out
def main():
model = MyNet()
model.build(input_shape=(None,32, 32,3))
model.summary()
if __name__ == '__main__':
main()
注意:这种方法需要在定义**input_shape=(None,32, 32,3)**时,考虑batch维度。
可以看出不是原生态的方法,导致summary的每层shape参数缺失。
关键点:对需要共享权重的网络进行实例化。
因为调用一次layers就会建立网络图,就会有相应的网络权重参数。
把需要共享权重部分的网络封装到一个子的Sequential() 或Model()中 ,或者单一层进行实例化,建立层的对象。
https://www.jianshu.com/p/4e45c7c4eb43
后续学习到TF1.0的静态图方式,再继续补充
网络训练传送门:
Tensorflow 2.* 网络训练(一) compile(optimizer, loss, metrics, loss_weights)
Tensorflow 2.* 网络训练(二) fit(x, y, batch_size, epochs, verbose, validation_split, initial_epoch… )
Tensorflow 2.* 网络训练(三) keras.callbacks 回调函数