tf.keras 学习<一>

0. tf.keras与Keras的关系与区别

Kras是Python编写的开源神经网络库。可以作为Tensorflow,Microsoft-CNTK和Theano的高阶应用程序接口,进行深度学的模型的设计,调试,评估,应用和可视化。它被设计为高度模块化和容扩展的高层神经网络接口。可以使得用户不需要过多的专业知识就可以简介,快速的完成模型的搭建和训练。

Keras库分为前端和后端,期中后端一般是调用现有的深度学习框架实现底层运算,前端接口是Keras抽象过的统一接口函数。

2015年,Tensorflow就被加入Keras后端支持。2019年,Tensorflow2版本中,Keras被证实确定为Tensorflow的高层唯一接口API。 取代了Tensorflow1版本中自带的tf.layers等高层接口。这就是tf.keras子模块。

1. tf.keras简介:

tf.keras是Tensorflow2.0的高阶API接口。为Tensorflow的代码提供了新的风格和设计模式。大大提升了TF代码的简洁性和复用性。官方也推荐使用tf.keras来进行模型的设计和开发。

常用模块:

模块    概述
activations    激活函数
applications    预训练网络模块
Callbacks    在模型训练期间被调用
datasets    tf.keras数据集模块,包括boston_housing,cifar10,fashion_mnist,imdb ,mnist
layers    Keras层API
losses    各种损失函数
metircs    各种评价指标
models    模型创建模块,以及与模型相关的API
optimizers    优化方法
preprocessing    Keras数据的预处理模块
regularizers    正则化,L1,L2等
utils    辅助功能实现
 

2. 使用tf.keras进行模型构建

有三种方法进行构建。

A. 简单模型使用Sequential进行构建。

B. 复杂模型使用函数式变成进行构建。

C. 自定义Layers (model的子类)构建.

2.1:使用Sequential构建模型

tf.keras是一个神经网络库。我们可以用它构建相应的神经网络。期中简单的神经网络如人工神经网络ANN这样简单的模型,可以用Sequential构建。

tf.keras.Sequenial模型是层的线性堆叠。它的构造函数会采用一系列层实例;

tf.keras 学习<一>_第1张图片

 例如:Layer1是输入层,Layer4是输出层。Layer2,Layer是隐藏层。

如图所示,可以构建2个密集层,分别包含5个节点,1个输出层,包含4个预测节点。第一个层的input_shape参数对应该数据集中的特征数量

import tensorflow as tf
from tensorflow.keras.models import Sequential
# import tensorflow.keras.utils
from tensorflow.keras import utils
from tensorflow.keras.layers import Dense


model = Sequential([
    #第一个隐藏层, 5个神经元,输入为3个特征. Dense表明是全连接层
    Dense(5, activation="relu", input_shape=(3,)),
    #第二个隐藏层, 5个神经元
    Dense(5, activation="relu"),
    #输出层, 4个分类。激活函数使用softmax
    Dense(4, activation="softmax")
],
    name = "My_Network"
)
model.summary()

# utils.plot_model(model, to_file='model.png', show_shapes=True, show_dtype=True,show_layer_names=True)

构建结果如下:

Model: "My_Network"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 5)                 20        
                                                                 
 dense_1 (Dense)             (None, 5)                 30        
                                                                 
 dense_2 (Dense)             (None, 4)                 24        
                                                                 
=================================================================
Total params: 74
Trainable params: 74
Non-trainable params: 0
_________________________________________________________________

2.2:利用tf.keras提供的API建立较为复杂的模型

建立于2.1同样的模型。使用Function API的方式。

import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers

#定义模型输入
Input_Layer = keras.Input(shape=(3,), name="input_1")
#第一个隐藏层
x = layers.Dense(5, activation = "relu", name="Layer1")(Input_Layer)
#第二个隐藏层
x = layers.Dense(5, activation="relu", name="Layer2")(x)

#输出层
Output_Layer = layers.Dense(4, activation ="softmax", name="Output")(x)

#创建模型
model = keras.Model(inputs = Input_Layer, outputs=Output_Layer, name="Functional API Model")

model.summary()

结果:

Model: "Functional API Model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_1 (InputLayer)        [(None, 3)]               0         
                                                                 
 Layer1 (Dense)              (None, 5)                 20        
                                                                 
 Layer2 (Dense)              (None, 5)                 30        
                                                                 
 Output (Dense)              (None, 4)                 24        
                                                                 
=================================================================
Total params: 74
Trainable params: 74
Non-trainable params: 0
_________________________________________________________________

2.3: model的子类进行构建

通过model的子类构建模型,在__init__中定义神经网络的层,在call方法中一定网络的前向传播方法。

import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers


class My_Models(keras.Model):
    #定义网络层结构
    def __init__(self):
        super(My_Models, self).__init__()
        #第一个隐藏层
        self.layer1 = layers.Dense(5, activation="relu", name="Layer1")
        # 第二个隐藏层
        self.layer2 = layers.Dense(5, activation="relu", name="Layer2")
        #定义输出层
        self.output_layer = layers.Dense(4, activation="softmax", name="Output")
    #定义网络的前向传播
    def __call__(self, inputs):
        x = self.layer1(inputs)
        x = self.layer2(x)
        outputs = self.output_layer(x)
        return outputs

#实例化
model1 = My_Models()
#设置输入
x = tf.ones((1, 4))
y = model1(x)

3. 使用tf.keras构建卷积神经网络

3.1: AlexNet网络架构

AlexNet使用了8层神经网络(5层卷积,2层全连接层,1个全连接输出层),以很大的优势赢得了ImageNet2012图像识别挑战赛,它首次证明了神经网络学习到的特征可以超越手工设计的特征。从而改变了计算机视觉研究的方向。(在此前,是研究如何找到更好的特征。此后,则是研究如何设计网络,以让网络能够更好的获取特征)

tf.keras 学习<一>_第2张图片

8层神经网络(5层卷积,2层全连接层,1个全连接输出层)

卷积核:第一个11x11. 第二个5x5.后面几个都是3x3. 

池化:3x3. stride=2.

激活函数使用relu.

全连接层加入dropout.

import tensorflow as tf
import tensorflow.keras as keras
from tensorflow.keras.models import Sequential
import tensorflow.keras.layers as layers
AlexNet = Sequential([
    #第一个卷积层11x11x96. 步长4.激活函数relu
    layers.Conv2D(filters=96, kernel_size=11, strides=4, activation="relu"),
    #池化 3x3. strides=2
    layers.MaxPool2D(pool_size=3, strides=2),

    #第二个卷积层5x5x256 padding=2
    layers.Conv2D(filters=256, kernel_size=5, padding="same", activation="relu"),
    #池化 3x3. strides=2
    layers.MaxPool2D(pool_size=3, strides=2),

    #第三个卷积层3x3x384. pad=1
    layers.Conv2D(filters=384, kernel_size=3, padding="same", activation="relu"),

    #第四个卷积层3x3x384. pad=1
    layers.Conv2D(filters=384, kernel_size=3, padding="same", activation="relu"),

    #第五个卷积层3x3x256. pad=1
    layers.Conv2D(filters=256, kernel_size=3, padding="same", activation="relu"),

    #池化 3x3. strides=2
    layers.MaxPool2D(pool_size=3, strides=2),

    #Flatten
    layers.Flatten(),

    #FC1. 4096. relu
    layers.Dense(4096, activation="relu"),

    layers.Dropout(0.5),

    #FC2 4096 relu
    layers.Dense(4096, activation="relu"),

    #Output
    layers.Dense(10, activation="softmax")

],
    name = "My_AlexNet"
)
# AlexNet.build(input_shape=[None,227,227,3])

# NHWC
x = tf.random.uniform((1,227,227,1))
y = AlexNet(x)


AlexNet.summary()

结果:

Model: "My_AlexNet"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (1, 55, 55, 96)           11712     
                                                                 
 max_pooling2d (MaxPooling2D  (1, 27, 27, 96)          0         
 )                                                               
                                                                 
 conv2d_1 (Conv2D)           (1, 27, 27, 256)          614656    
                                                                 
 max_pooling2d_1 (MaxPooling  (1, 13, 13, 256)         0         
 2D)                                                             
                                                                 
 conv2d_2 (Conv2D)           (1, 13, 13, 384)          885120    
                                                                 
 conv2d_3 (Conv2D)           (1, 13, 13, 384)          1327488   
                                                                 
 conv2d_4 (Conv2D)           (1, 13, 13, 256)          884992    
                                                                 
 max_pooling2d_2 (MaxPooling  (1, 6, 6, 256)           0         
 2D)                                                             
                                                                 
 flatten (Flatten)           (1, 9216)                 0         
                                                                 
 dense (Dense)               (1, 4096)                 37752832  
                                                                 
 dropout (Dropout)           (1, 4096)                 0         
                                                                 
 dense_1 (Dense)             (1, 4096)                 16781312  
                                                                 
 dense_2 (Dense)             (1, 10)                   40970     
                                                                 
=================================================================
Total params: 58,299,082
Trainable params: 58,299,082
Non-trainable params: 0
_________________________________________________________________

3.2: ResNet网络架构

ResNet是2015年ImageNet冠军。 错误率低于人类。

理论上,网络越深,获取的信息就越多,特征也越丰富,效果应该越好。但在实践中,随着网络的层数增加,有时优化效果反而越差。针对这一问题,提出了残差网络(ResNet).在2015年ImageNet图像识别挑战赛夺得冠军,深刻影响了后来的深度神经网络的设计。

 ResNet的核心思想就是引入了残差边。即一条直接从输入添加到输出的边。

tf.keras 学习<一>_第3张图片

这条边shortcut,有时需要1x1卷积。下面图的虚线shortcut,就是有1x1卷积的。

假如新加的这些层的学习效果非常差,那我们就可以通过一条残差边将这一部分直接“跳过”。实现这一目的很简单,将这些层的权重参数设置为0就行了。这样一来,不管网络中有多少层,效果好的层我们保留,效果不好的我们可以跳过。总之,添加的新网络层至少不会使效果比原来差,就可以较为稳定地通过加深层数来提高模型的效果了。

  此外,使用残差边的另一个好处在于可以避免梯度消失的问题。因为它的这个特点,它可以训练几百甚至上千层的网络
 

ResNet沿用了VGG全3x3卷积层的设计。

层数较少的神经网络中:残差块里首先有2个相同输出通道的3x3卷积层。每个卷积层后接BN层和Relu激活函数。再将输入直接加到最后的Relu激活函数前。

若输入通道数较多,就需要引入1x1卷积层来调整输入的通道数。常用于网络层数较多的结构。

残差块实现代码:

ResNet18模型结构:

tf.keras 学习<一>_第4张图片

ResNet18. 共有4组(每组4个)卷积层,加上开始的7x7卷积层和全连接层。共18层。所以叫ResNet18. (不包含1x1卷积层)。

注意,如果不是第一组残差模块,且又是第一个残差块,则残差块需要做1x1卷积,以实现通道数和宽高的调整。(见虚线)

不同颜色的卷积层,构成不同的残差模块。

残差网络,就是一系列残差块串联的结果。

import tensorflow as tf
from tensorflow.keras import activations
import tensorflow.keras.layers as layers
#残差块构成
#两个同输出的conv. 第一个conv+BN+激活函数。 第二个conv+BN后,结果与输入x相加, 再使用激活函数
class Residual(tf.keras.Model):
    #定义网络结构
    def __init__(self, num_channels, use_1x1conv=False, strides=1):
        super(Residual, self).__init__()

        #第一个卷积层
        self.conv1 = layers.Conv2D(num_channels, padding="same", kernel_size=3, strides=strides)
        #第二个卷积层
        self.conv2 = layers.Conv2D(num_channels, kernel_size=3, padding = "same")

        #是否使用1x1卷积层
        if(use_1x1conv):
            self.conv3 = layers.Conv2D(num_channels, kernel_size= 1, strides=strides)
        else:
            self.conv3 = None

        #BN
        self.bn1 = layers.BatchNormalization()
        self.bn2 = layers.BatchNormalization()




    #定义前向传播过程
    def call(self, x):
        Y = activations.relu(self.bn1(self.conv1(x)))
        Y = self.bn2(self.conv2(Y))
        if (self.conv3):
            x = self.conv3(x)
        outputs = activations.relu(x+Y)
        return outputs


#残差模块. 每个残差模块包含多个(2个)残差块,每个残差快包含2个conv层
class Resnet_Block(tf.keras.layers.Layer):
    #定义所需的网络结构. num_channels, num_res:残差模块中的残差块个数, first_block:是不是第一个残差模块
    def __init__(self, num_channels, num_res, first_block=False):
        super(Resnet_Block, self).__init__()
        #存储残差块
        self.listLayers = []
        #遍历残差块数量
        for i in range(num_res):
            #如果是第一个残差块,并且不是第一个残差模块时
            if(i == 0 and not first_block):
                self.listLayers.append(Residual(num_channels, use_1x1conv=True, strides=2))
            else:
                self.listLayers.append(Residual(num_channels))

        
    #定义前向传播
    def call(self, X):
        for layer in self.listLayers.layers:
            X = layer(X)
        return X


#构建ResNet
#前面分别定义了残差块(2conv)和残差模块,现在把残差7x7卷积+4个残差模块+FC, 就构成了RestNet18
class ResNet(tf.keras.Model):
    #定义网络构成. num_blocks: list,依次指定没一个残差模块中残差快的个数
    def __init__(self, num_blocks):
        super(ResNet, self).__init__()
        #7x7卷积
        self.conv = layers.Conv2D(64, kernel_size=7, strides=2, padding="same")
        #BN层
        self.bn = layers.BatchNormalization()
        #激活层
        self.relu = layers.Activation("relu")
        #池化
        self.mp = layers.MaxPool2D(pool_size=3, strides=2, padding="same")

        #串联残差模块
        #残差模块1
        self.res_block1=Resnet_Block(64,num_blocks[0], first_block=True)
        #残差模块2
        self.res_block2=Resnet_Block(128, num_blocks[1], first_block=False)
        #残差模块3
        self.res_block3 = Resnet_Block(256, num_blocks[2], first_block=False)
        # 残差模块4
        self.res_block4 = Resnet_Block(512, num_blocks[3], first_block=False)

        #平均池化
        self.gap = layers.GlobalAvgPool2D()
        #FC
        self.fc = layers.Dense(units=10, activation=tf.keras.activations.softmax)


    def call(self, x):
        #输入部分的传输过程
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        x = self.mp(x)

        #Res block
        x =self.res_block1(x)
        x = self.res_block2(x)
        x = self.res_block3(x)
        x = self.res_block4(x)
        #输出部分的传输
        x = self.gap(x)
        x = self.fc(x)
        return x

#实例化
mynet = ResNet([2,2,2,2])
X = tf.random.uniform([1,224,224,1])
y = mynet(X)
mynet.summary()

Model: "res_net"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             multiple                  3200      
                                                                 
 batch_normalization (BatchN  multiple                 256       
 ormalization)                                                   
                                                                 
 activation (Activation)     multiple                  0         
                                                                 
 max_pooling2d (MaxPooling2D  multiple                 0         
 )                                                               
                                                                 
 resnet__block (Resnet_Block  multiple                 148736    
 )                                                               
                                                                 
 resnet__block_1 (Resnet_Blo  multiple                 526976    
 ck)                                                             
                                                                 
 resnet__block_2 (Resnet_Blo  multiple                 2102528   
 ck)                                                             
                                                                 
 resnet__block_3 (Resnet_Blo  multiple                 8399360   
 ck)                                                             
                                                                 
 global_average_pooling2d (G  multiple                 0         
 lobalAveragePooling2D)                                          
                                                                 
 dense (Dense)               multiple                  5130      
                                                                 
=================================================================
Total params: 11,186,186
Trainable params: 11,178,378
Non-trainable params: 7,808
_________________________________________________________________

你可能感兴趣的:(Python,tensorflow,keras,学习,深度学习)