Tensorflow 2.0 中模型构建的三种方式(三种模型的定义方式)

文章目录:

1. 三种定义模型的方式

keras和tensorflow2.0提供了三种定义模型的方式:

a. Sequential API
b. Functional API
c. Subclassing API

这就需要我们了解如何使用这三种方法来定义模型,还要学会什么时候该用什么方法

2. 三种方式使用的优先级

先考虑能不能用Keras Sequential APIs 方式建立需要的模型,如果不能,在考虑能不能使用Keras Functional APIs方式来建立你需要的模型,如果还是不能,最后再考虑Keras Model Subclassing APIs方式

3. 三种模型的定义方式

3.1 Sequential API

当我们想到神经网络时,我们通常使用的模型是一个“层图”,如下图:
在这里插入图片描述
这个图可以是左边显示的有向无环图,也可以是右边显示的堆叠形式,我们使用符号来构建模型时,我们通过描述这个图的结构来实现。
下面是keras序列化API符号化构建模型的快速示例:
在这里插入图片描述
在上面的示例中,我们定义了一组层,然后使用内置的训练循环model.fit对其进行训练
用keras构建模型就像“把乐高积木塞在一起”一样简单。为什么,除了匹配我们认知的模型外,以这种方式构建的模型很容易调试
在这里插入图片描述
图中显示了上面代码创建的模型(使用plot_model构建)。
序列模型是layer-by-layer的,它是最简单的定义模型的方法,但是有几个不足:
• 不能够共享某一层
• 不能有多个分支
• 不能有多个输入
这种结构的经典网络比如有:Lenet5,AlexNet,VGGNet
定义一个简单的Sequential模型

#导入必备包
import tensorflow as tf
from tensorflow.keras.models import Model,Sequential
from tensorflow.keras.layers import Conv2D,Maxpooling2D,AveragePooling2D,BatchNormalization,Activation,Dropout,Flatten,Input,Dense,concatenate
#开始定义模型 
def shallownet_sequential(width,height,depth,classes):     
	#channel last,用输入形状来初始化模型     
	model = Sequential()     
	inputshape=(height,width,depth)     
	model.add(Conv2D(32,(3,3),padding='same',input_shape=inputshape))     
	model.add(Activation("relu"))          
	#softmax     
	model.add(Flatten())     
	model.add(Dense(classes))     
	model.add(Activation("softmax"))     
	return model 

使用和实例化

model = shallownet_sequential(width,height,depth,classes)
outputs = model(inputs)

3.2 Functional API

TensorFlow 2.0提供了另一个符号模型构建api:Keras Functional。序列化用于堆叠,你可能已经猜到了,函数用于DAGs。
在这里插入图片描述
一个快速的示例,使用函数API创建一个多输入/多输出模型
函数API是一种创建更灵活模型的方法。它可以处理非线性拓扑、具有共享层的模型和具有多个输入或输出的模型。
函数式API有更强的功能
• 定义更复杂的模型
• 支持多输入多输出
• 可以定义模型分支,比如inception block , resnet block
• 方便layer共享
另外,对于任意的Sequential模型,都可以用函数式编程方式来实现。
函数式模型示例有:

• ResNet
• GoogleNet/Inception
• Xception
• SqueezeNet

下面定义一个mini的GoogleNet,原文参见文档
1.comv_module:卷积模块,进行卷积,batchnorm,relu的操作,定义模块,方便复用。
2.inception_module:包括两个卷积模块,卷积核以(3,3)和(1,1)实现,padding=same,两个通道的输出会被拼接起来。
3.downsample_module:作用是减小尺寸。有两个分支:一个是卷积下采样,33的卷积核,stride=22,padding=‘valid’。另一个下采样方法是最大值池化,pool_size=33,strides=22,padding=valid,最后的输出拼接起来。
实现以上三种模块,然后通过各种组合,组成模型

def conv_module(x,k,kx,ky,stride,chandim,padding="same"):
    #conv-bn-relu
    x = Conv2D(k,(kx,ky),strides=stride,padding=padding)(x)
    x = BatchNormalization(axis=chandim)(x)
    x = Activation('relu')(x)
    return x
def inception_module(x,num1x1,num3x3,chandim):
    conv_1x1 = conv_module(x,num1x1,1,1,(1,1),chandim)
    conv_3_3 = conv_module(x,num3x3,3,3,(1,1),chandim)
    x = concatenate([conv_1x1,conv_3_3],axis=chandim)
    return x
def downsample_module(x,k,chandim):
    #conv downsample and pool downsample
    conv_3x3 = conv_module(x,k,3,3,(2,2),chandim,padding='valid')
    pool = MaxPooling2D((3,3),strides=(2,2))(x)
    x = concatenate([conv_3x3,pool],axis=chandim)
    return x
#然后定义整个MiniGoogLeNet
def minigooglenet_functional(width,height,depth,classes):
    inputshape=(height,width,depth)
    chandim=-1
    #define inputs and firse conv
    inputs = Input(shape=inputshape)
    x = conv_module(inputs,96,3,3,(1,1),chandim)
    #def two inception and followed by a downsample
    x = inception_module(x,32,32,chandim)
    x = inception_module(x,32,48,chandim)
    x = downsample_module(x,80,chandim)
    #def four inception and one downsample
    x = inception_module(x,112,48,chandim)
    x = inception_module(x,96,64,chandim)
    x = inception_module(x,80,80,chandim)
    x = inception_module(x,48,96,chandim)
    x = downsample_module(x,96,chandim)
    #def two inception followed by global pool and dropout
    x = inception_module(x,176,160,chandim)
    x = inception_module(x,176,160,chandim)
    x = AveragePooling2D((7,7))(x)
    x = Dropout(0.5)(x)
    #softmax
    x = Flatten()(x)
    x = Dense(classes)(x)
    x = Activation('softmax')(x)
 
    #create the model
    model = Model(inputs,x,name='MiniGoogLeNet')
    return model

实例化和使用

model = minigooglenet_functional(32,32,3,10)
y = model(x)

3.3 Subclassing API

在命令式中,可以像NumPy那样编写模型,用这种风格构建模型感觉像面向对象编程。下面是一个子类模型的快速例子:
在这里插入图片描述
从开发人员的角度来看,这种工作方式是扩展框架定义的模型类,实例化层,然后编写模型的正向传递(自动生成向后传递)
TensorFlow 2.0通过Keras Subclassing API支持这种开箱即用的方式。在keras中Model类做为基本的类,可以在些基础上,进行会任意个人设置,带来很强的自由。但同进带来的不足就是没用序列和函数定义模型使用起来简单。既然子类方法有些难,为什么还要用呢,因为这对一些研究人员很好,可以模型所以部分进行控制。

lass MyModel(tf.keras.Model):
    def __init__(self):
       super().__init__()
       # 此处添加初始化代码(包含call方法中会用到的层),例如
       # layer1 = tf.keras.layers.BuiltInLayer(...)
        # layer2 = MyCustomLayer(...)
    def call(self, input):
        # 此处添加模型调用的代码(处理输入并返回输出),例如
        # x = layer1(input)
        # output = layer2(x)
       return output
  # 还可以添加自定义的方法

Keras 模型类定义示意图
在这里插入图片描述
继承 tf.keras.Model 后,我们同时可以使用父类的若干方法和属性,例如在实例化类 model = Model() 后,可以通过 model.variables 这一属性直接获得模型中的所有变量,免去我们一个个显式指定变量的麻烦。
简单的线性模型 y_pred = a * X + b ,我们可以通过模型类的方式编写如下:

import tensorflow as tf
X = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
 y = tf.constant([[10.0], [20.0]])
class Linear(tf.keras.Model):
   def __init__(self):
        super().__init__()
       self.dense = tf.keras.layers.Dense(
            units=1,
            activation=None,
            kernel_initializer=tf.zeros_initializer(),
            bias_initializer=tf.zeros_initializer()
        )
    def call(self, input):
        output = self.dense(input)
       return output
# 使用
model = Linear()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
for i in range(100):
    with tf.GradientTape() as tape:
        y_pred = model(X)      # 调用模型 y_pred = model(X) 而不是显式写出 y_pred = a * X + b
        loss = tf.reduce_mean(tf.square(y_pred - y))
    grads = tape.gradient(loss, model.variables)    # 使用 model.variables 这一属性直接获得模型中的所有变量
    optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))
print(model.variables)

这里,我们没有显式地声明 a 和 b 两个变量并写出 y_pred = a * X + b 这一线性变换,而是建立了一个继承了 tf.keras.Model 的模型类 Linear 。这个类在初始化部分实例化了一个 全连接层 (tf.keras.layers.Dense ),并在 call 方法中对这个层进行调用,实现了线性变换的计算。
Keras 的全连接层:线性变换 + 激活函数
全连接层 (Fully-connected Layer,tf.keras.layers.Dense ) 是 Keras 中最基础和常用的层之一,对输入矩阵 进行 的线性变换 + 激活函数操作。如果不指定激活函数,即是纯粹的线性变换 。具体而言,给定输入张量 input = [batch_size, input_dim] ,该层对输入张量首先进行 tf.matmul(input, kernel) + bias 的线性变换 ( kernel和 bias 是层中可训练的变量),然后对线性变换后张量的每个元素通过激活函数 activation ,从而输出形状为 [batch_size, units] 的二维张量。
在这里插入图片描述
在这里插入图片描述

4. 训练模式(training mode)和推理模式(inference mode)下模型的使用

4.1 Keras Sequential 方式构建的模型

这种方式构建的实例model,在training mode下,可以直接使用model(inputs,training=True);在inference mode 下,可以直接使用model(inputs,training=False),
我们知道,在Python中对类的实例 class_object进行形如class_object()的调用,等价于class_object.call()。而在Tensorflow中,call()方法中又调用了call()方法,这个方法才是我们关注点所在
我们可以通过help函数来查看一下该call()方法的用法(可以看到training参数):

>>> help(tf.keras.Sequential.call)
Help on function call in module tensorflow.python.keras.engine.sequential:
call(self, inputs, training=None, mask=None)
    Calls the model on new inputs.
In this case `call` just reapplies all ops in the graph to the new inputs
    (e.g. build a new computational graph from the provided inputs).
Arguments:
        inputs: A tensor or list of tensors.
        training: Boolean or boolean scalar tensor, indicating whether to run the `Network` in training mode or inference mode.
        mask: A mask or list of masks. A mask can be either a tensor or None (no mask).
Returns:
        A tensor if there is a single output, or a list of tensors if there are more than one outputs.

4.2 Keras Functional API方式构建的模型

这种方式构建的实例model,在training mode下,也是直接使用model(inputs,training=True);在inference mode 下,也是直接使用model(inputs,training=False).
我们可以通过help函数来查看一下该call()方法的用法(可以看到training参数):

>>> help(tf.keras.Model.call)
Help on function call in module tensorflow.python.keras.engine.network:
call(self, inputs, training=None, mask=None)
    Calls the model on new inputs.
In this case `call` just reapplies all ops in the graph to the new inputs
    (e.g. build a new computational graph from the provided inputs).
Arguments:
        inputs: A tensor or list of tensors.
        training: Boolean or boolean scalar tensor, indicating whether to run the `Network` in training mode or inference mode.
        mask: A mask or list of masks. A mask can be either a tensor or None (no mask).
Returns:
        A tensor if there is a single output, or a list of tensors if there are more than one outputs.

4.3 Keras Model Subclassing 方式构建的模型

使用这种方式构建模型,有个特点,就是在模型类中必须手工重载实现其call()方法,换句话来说,就是call()方法的参数training必须由自己来管理,如下例子:

class self_model(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.flatten = tf.keras.layers.Flatten()   
        self.dense1 = tf.keras.layers.Dense(units=100)
        self.bn = tf.keras.layers.BatchNormalization()
        self.dense2 = tf.keras.layers.Dense(units=10)
 
    def call(self, inputs, training=None):         
        x = self.flatten(inputs)    
        x = tf.nn.relu(self.bn(self.dense1(x), training=training))  
        output = tf.nn.softmax(self.dense2(x))
        return output

在上面这个例子中,BatchNormalization层的实例self.bn在调用过程中给,需要我们手工传入training参数,使得它在训练模式和推理模式表现出不同的行为。
而在前面两种构建模型的方式中,我们不需要手工管理training参数,只需要在使用模型类实例model时,隐式调用其call()方法,传入正确的training参数值即可。Tensorflow在底层构建模型是就会根据我们传入的training参数值,自动给BatchNormalization层和dropout层赋予不同的行为。
前面两种构建模型的方式中,我们不需要在模型内部调用BatchNormalization层时传入training参数值,只需要在模型实例化时,传入,而第三种方式需要。

5. 总结

a. sequential的方式用来实现一层接着一层的模型
b. functional的模型能完成大多数模型
c. subclassing的模型能完全自定义,但是比较复杂 所常归来说,用functional就好了。

5.1 符号APIs的好处和局限性

5.1.1好处

使用符号APIs,模型是类似于图的数据结构,这意味着可以检查或者总结模型(你可以将它挥着为一个图像来显示图(使用keras.utils.plot_model)或者简单的使用model.summary(),或者查看图层、权重和形状描述。)
同样,当将层连接在一起时,库设计人员可以运行兼容性检查(在构建模型时和执行之前)
• 这类似于编译器中的类型检查,可以极大地减少开发人员的错误。
• 大多数调试将在模型定义阶段进行,而不是在执行阶段。你可以保证任何编译的模型都会运行。这使得迭代更快,调试更容易

符号模型提供一致的API。这使得它们易于重用和共享。例如,在迁移学习中,你可以访问中间层激活来从现有的模型构建新的模型,如下所示:

from tensorflow.keras.applications.vgg19 import VGG19        
base = VGG19(weights=’imagenet’)        
model = Model(inputs=base.input,outputs=base_model.get_layer(‘block4_pool’).output)
image = load(‘elephant.png’)        
block4_pool_features = model.predict(image)

符号模型是由数据结构定义的,这使得它们可以自然地复制或克隆。

例如,序列化api和函数api为你提供了model.get_config()、 model.to_json() 、model.save()、clone_model(model)等功能,可以从数据结构中重新创建相同的模型(无需访问用于定义和训练模型的原始代码)。

虽然一个设计良好的API应该匹配我们的神经网络模型,但同样重要的是匹配我们作为程序员的心智模型。对于我们许多人来说,这是一种命令式的编程风格。在符号API中,你在操作“符号张量”(这些张量尚未包含任何值)来构建图形。Keras序列化API和函数API“感觉到”命令。它们的设计使得许多开发人员没有意识到他们一直在使用符号来定义模型。

5.1.2 局限性

当前生成的符号api是最适合开发的有向无环图模型。这在实践中占了大多数用例,尽管有一些特殊的用例不适合这种简洁的抽象,例如,动态网络(如树状rnns)和递归网络。

这就是为什么TensorFlow还提供了一种命令式的模型构建API风格(Keras子类化,如上所示)。你可以使用序列化api和函数api中所有熟悉的层、初始化器和优化器。这两种样式也是完全可互操作的,因此你可以混合和匹配(例如,你可以将一种模型类型嵌套到另一种模型类型中)。你可以将符号模型用作子类模型中的一个层,或者反过来。

5.2命令式APIs的好处和局限性

5.2.1 好处

你的前向传递是强制编写的,这使得用你自己的实现替换库实现的部件(例如,层、激活或丢失函数)变得很容易。这对于编程来说是很自然的,也是深入学习深层知识的好方法。

这使得快速尝试新想法变得容易(DL开发工作流变得与面向对象的Python相同),并且对研究人员特别有帮助。

使用Python,在模型的正向传递中指定任意控制流也很容易。

命令式api为你提供了最大的灵活性,但这是有代价的。我也喜欢用这种风格编写代码,但是我想花点时间来强调一下它的局限性(注意权衡利弊是有好处的)。

5.2.2 局限性

重要的是,在使用命令式API时,模型是由类方法的主体定义的。你的模型不再是透明的数据结构,而是一段不透明的字节码。当使用这种风格时,你是在用可用性和重用性来换取灵活性。

调试发生在执行过程中,而不是在定义模型时。

几乎没有对输入或层间兼容性的检查,所以当使用这种风格时,很多调试负担从框架转移到开发人员身上。

命令式模型可能更难于重用。例如,你不能使用一致的API访问中间层或激活。

相反,提取激活的方法是用新的调用(或前向)方法编写一个新类。最初写可能很有趣,也很简单,但如果没有标准,它可能会为以后埋坑。

命令式模型也更难于检查、复制或克隆。

例如,model.save()、model.get_config()和clone_model不能用于子类化的模型。类似地,model.summary()只给出一个层列表(不提供关于它们如何连接的信息,因为这是不可访问的)。

重要的是要记住,模型构建只是在实践中使用机器学习的一小部分。
模型本身(指定层、训练循环等的代码部分)是位于中间的小框。
在这里插入图片描述

在实际的ML系统中,只有一小部分由ML代码组成,如中间的小黑盒子所示
符号定义的模型在可重用性、调试和测试方面具有优势。例如,在教学的时候,如果他们使用序列化API,我可以立即调试学生的代码。当他们使用子类模型时(不管框架是什么),会花费更长的时间(bug可能更微妙,而且有很多类型)。
TensorFlow 2.0支持这两种样式,所以你可以为你的项目选择合适的抽象级别(和复杂性)。

• 如果你的目标是易用性、低概念开销,并且你喜欢将模型看作层图:使用Keras序列化API或函数API(如将LEGO积木连接在一起)和内置的训练循环。这是解决大多数问题的正确方法。

• 如果你想把你的模型看作一个面向对象的Python/Numpy开发人员,并且你优先考虑灵活性和可编程性,Keras子类化是适合你的API。

6. 参考文章

https://blog.csdn.net/u011119817/article/details/102922269
https://blog.csdn.net/u011984148/article/details/99440017
https://blog.csdn.net/weixin_42398658/article/details/94558546
https://zhuanlan.zhihu.com/p/99936722
https://blog.csdn.net/zkbaba/article/details/100172705
https://www.jianshu.com/p/f5510ecdcc28
http://www.360doc.com/content/19/0717/23/32196507_849458543.shtml

  • 29
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: Python的TensorFlow 2.0 Demo是一个展示和演示TensorFlow 2.0的示例程序。TensorFlow是一个开源的机器学习框架,它提供了丰富的工具和库,用于构建和训练各种人工智能模型TensorFlow 2.0 Demo可以帮助我们了解如何使用Python编写TensorFlow代码,构建和训练模型。在Demo,我们可以看到一些预先定义好的模型,如卷积神经网络(CNN)和循环神经网络(RNN),以及一些常见的数据集,如MNIST手写数字数据集。 Demo的代码可以帮助我们学习如何使用TensorFlow 2.0的新特性,如Eager Execution和tf.keras API。Eager Execution使得TensorFlow代码更加直观和易于调试,而tf.keras API提供了一种方便的方式定义和训练神经网络模型。 另外,Demo还可以帮助我们了解TensorFlow 2.0的一些新功能,如动态图(Dynamic Graph)和AutoGraph。动态图允许我们动态地构建和修改计算图,而AutoGraph则可以将Python代码自动转化为高效的TensorFlow计算图。 通过运行TensorFlow 2.0 Demo,我们可以学习到如何使用Python和TensorFlow构建和训练机器学习模型,并熟悉TensorFlow 2.0的一些新特性和功能。这对于想要进一步了解和掌握深度学习和人工智能的人来说非常有帮助。 ### 回答2: Python TensorFlow 2.0 Demo 是一个用于展示 TensorFlow 2.0 版本的 Python 示例的演示程序。它旨在向用户展示如何使用 TensorFlow 2.0 进行机器学习和深度学习任务。 Python TensorFlow 2.0 Demo 演示了 TensorFlow 2.0 在数据处理、模型构建和训练等方面的功能。通过这个示例,用户可以了解 TensorFlow 2.0 的主要特点和用法。 在数据处理方面,Python TensorFlow 2.0 Demo 提供了许多常用的数据处理功能,例如加载数据集、数据集预处理、数据增强等。这些功能可以帮助用户准备数据用于模型的训练和评估。 在模型构建方面,Python TensorFlow 2.0 Demo 展示了如何使用 TensorFlow 2.0 构建各种类型的神经网络模型,包括卷积神经网络(CNN)、循环神经网络(RNN)和变分自编码器(VAE)等。用户可以学习如何定义模型的结构和参数,并将其编译为可训练的 TensorFlow 图。 在模型训练方面,Python TensorFlow 2.0 Demo 展示了如何使用 TensorFlow 2.0 进行模型的训练和评估。用户可以学习如何选择合适的优化器、损失函数和评估指标,并使用训练数据集对模型进行训练,并使用测试数据集对其进行评估。 总而言之,Python TensorFlow 2.0 Demo 可以帮助用户了解并学习如何使用 TensorFlow 2.0 进行机器学习和深度学习任务。通过这个演示程序,用户可以掌握 TensorFlow 2.0 的基本用法,并在实践探索更多高级的功能和技巧。 ### 回答3: Python TensorFlow 2.0 是一个强大的深度学习框架,可以用于构建和训练各种机器学习模型。使用 Python TensorFlow 2.0,可以轻松地创建端到端的模型,处理大规模的数据集,以及进行模型的训练和推理。 在 TensorFlow 2.0 ,与之前版本相比,有一些重要的改进和新功能。其最重要的是 Eager Execution(即动态图执行),它使得在 TensorFlow 编写代码更加直观和简单,可以立即获得结果的反馈。另外,TensorFlow 2.0 还引入了一种新的高级 API——Keras,它提供了更简洁、易用的方式定义和训练神经网络模型。 使用 TensorFlow 2.0 可以轻松地构建各种机器学习模型。例如,可以使用 TensorFlow 2.0 构建一个图像分类模型,对图像进行分类。首先,需要准备训练集和测试集的图像数据,然后使用 TensorFlow 2.0 的 Keras API 构建一个卷积神经网络模型。接下来,编写代码对模型进行训练,并使用测试集进行验证。通过迭代和调整模型的参数,可以获得更好的分类效果。 在实际使用 TensorFlow 2.0 进行机器学习任务时,通常还会使用一些其他的库和工具来辅助。例如,可以使用 NumPy 来处理和转换数据,使用 Matplotlib 来可视化结果,使用 Pandas 来进行数据处理和分析等等。同时,也可以利用 TensorFlow 的高级特性,如分布式训练和自定义损失函数等,来进一步提升模型的性能和效果。 总而言之,Python TensorFlow 2.0 是一个功能强大、易用的深度学习框架,可用于构建和训练各种机器学习模型。通过灵活的应用和结合其他工具和库,可以实现各式各样的机器学习任务,并获得良好的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值