这个问题的目的是寻求一个最低限度的指南来使某人快速使用TensorFlow 1和TensorFlow2。我觉得没有一个连贯的指南可以解释TF1和TF2之间的差异,而TF已经通过主要修订和快速发展。

供我引用时,

  • v1或TF1-我指的是TF 1.15.0
  • v2或TF2-我指的是TF 2.0.0

  • 我的问题是
  • TF1/TF2如何工作?他们的主要区别是什么?
  • TF1和TF2中有哪些不同的数据类型/数据结构?
  • 什么是Keras,它如何适合所有这些? Keras提供了哪些不同的API来实现深度学习模型?您能否提供每个示例?
  • 使用TF和Keras时最需要注意的是哪些经常出现的警告/错误?
  • TF1和TF2之间的性能差异
  • 最佳答案

    TF1/TF2如何工作?和他们之间的差异

    TF1

    TF1遵循一种称为define-then-run的执行方式。这与“运行定义”相反,例如,“Python定义”执行样式。但是,这是什么意思?定义然后运行意味着,仅因为您调用/定义了某项而未执行。您必须明确执行定义的内容。

    TF具有图的概念。首先,定义所需的所有计算(例如,神经网络的所有层计算,损失计算以及使损失最小化的优化器-这些表示为操作或操作)。定义计算/数据流图之后,您可以使用Session执行这些操作。让我们来看一个简单的例子。

    # Graph generation
    tf_a = tf.placeholder(dtype=tf.float32)
    tf_b = tf.placeholder(dtype=tf.float32)
    tf_c = tf.add(tf_a, tf.math.multiply(tf_b, 2.0))
    
    # Execution
    with tf.Session() as sess:
        c = sess.run(tf_c, feed_dict={tf_a: 5.0, tf_b: 2.0})
        print(c)
    

    计算图(也称为数据流图)如下所示。
         tf_a      tf_b   tf.constant(2.0)
           \         \   /
            \      tf.math.multiply
             \     /
             tf.add
                |
              tf_c
    

    类比:考虑您做蛋糕。您可以从互联网上下载配方。然后,您开始执行实际制作蛋糕的步骤。配方就是图表,制作蛋糕的过程就是 session 执行的操作(即图表的执行)。

    TF2

    TF2遵循立即执行样式或按运行定义。您调用/定义一些东西,它就被执行了。让我们来看一个例子。
    a = tf.constant(5.0)
    b = tf.constant(3.0)
    c = tf_a + (tf_b * 2.0)
    print(c.numpy())
    

    哇!与TF1示例相比,它看起来如此干净。一切看起来都像Python一样。

    类比:现在认为您正在动手做蛋糕工作坊。您正在按照老师的说明做蛋糕。然后讲师立即解释每个步骤的结果。因此,与前面的示例不同,您不必等到烤蛋糕就看是否做对了(这是无法调试代码的事实的引用)。但是您会得到有关您的表现的即时反馈(您知道这意味着什么)。

    这是否意味着TF2无法建立图表?惊恐发作

    是的,不是。关于eager executionAutoGraph函数,您应该了解TF2中的两个功能。



    急于执行

    急切的执行可以立即执行TensorOperation。这是您在TF2示例中观察到的。但不利的一面是,它没有建立图表。因此,例如,您使用急切的执行来实现和运行神经网络,它将非常慢(因为神经网络一遍又一遍地执行非常重复的任务(正向计算-损失计算-向后传递)。

    签名

    这就是自动图形功能的急救之处。 AutoGraph是TF2中我最喜欢的功能之一。这样做的作用是,如果您在函数中执行“TensorFlow”操作,它将分析该函数并为您构建图形(烦死了)。因此,例如,您执行以下操作。 TensorFlow构建图。
    @tf.function
    def do_silly_computation(x, y):
        a = tf.constant(x)
        b = tf.constant(y)
        c = tf_a + (tf_b * 2.0)
        return c
    
    print(do_silly_computation(5.0, 3.0).numpy())
    

    因此,您所需要做的就是定义一个函数,该函数接受必要的输入并返回正确的输出。最重要的是添加@tf.function装饰器,因为这是TensorFlow AutoGraph分析给定功能的触发器。



    TF1和TF2之间的区别
  • TF1需要tf.Session()对象来执行图形,而TF2不需要
  • 在TF1中,未引用的变量不是由Python GC收集的,但是在TF2中,它们是
  • TF1不会提升代码模块化,因为在开始计算之前,您需要定义完整的图形。但是,使用AutoGraph函数可以鼓励模块化代码

  • TF1和TF2中有哪些不同的数据类型?

    您已经看过许多主要的数据类型。但是您可能对它们的功能以及行为方式有疑问。好了,本节就是关于这一点的。

    TF1数据类型/数据结构
  • tf.placeholder:这是您向计算图提供输入的方式。顾名思义,它没有附加值。而是在运行时输入值。 tf_atf_b是这些示例。将此视为一个空盒子。您可以根据需要将水/沙/蓬松的泰迪熊装满。
  • tf.Variable:这是您用来定义神经网络参数的方法。与占位符不同,变量使用一些值初始化。但是它们的值(value)也可以随着时间而改变。这就是在反向传播过程中神经网络的参数发生的情况。
  • tf.Operation:操作是可以在占位符,张量和变量上执行的各种转换。例如tf.add()tf.mul()是操作。这些操作(大多数情况下)返回张量。如果您想证明操作不返回张量,请检查this
  • tf.Tensor:就其具有初始值而言,它类似于变量。但是,一旦定义它们,它们的值就无法更改(即它们是不可变的)。例如,上一个示例中的tf_ctf.Tensor

  • TF2数据类型/数据结构
  • tf.Variable
  • tf.Tensor
  • tf.Operation

  • 就行为而言,从TF1到TF2的数据类型没有太大变化。唯一的主要区别是,tf.placeholders不见了。您也可以看看full list of data types

    什么是Keras,它如何适合所有这些?

    Keras曾经是一个单独的库,提供主要用于深度学习模型的组件(例如层和模型)的高级实现。但是从TensorFlow的更高版本开始,Keras已集成到TensorFlow中。

    因此,正如我所解释的,如果要使用裸骨TensorFlow,Keras隐藏了许多不必要的复杂处理。 Keras为实现NN提供了主要的两件事Layer对象和Model对象。 Keras还具有两个最常见的模型API,可用于开发模型:顺序API和功能API。在一个简单的示例中,让我们看看Keras和TensorFlow有何不同。让我们构建一个简单的CNN。


    height=64
    width = 64
    n_channels = 3
    n_outputs = 10
    

    Keras(顺序API)示例
    model = Sequential()
    model.add(Conv2D(filters=32, kernel_size=(2,2),
    activation='relu',input_shape=(height, width, n_channels)))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Conv2D(filters=64, kernel_size=(2,2), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Flatten())
    model.add(Dense(n_outputs, activation='softmax'))
    model.compile(loss='binary_crossentropy', optimizer='adam')
    model.summary()
    

    优点



    缺点



    Keras(功能性API)示例
    inp = Input(shape=(height, width, n_channels))
    out = Conv2D(filters=32, kernel_size=(2,2), activation='relu',input_shape=(height, width, n_channels))(inp)
    out = MaxPooling2D(pool_size=(2,2))(out)
    out = Conv2D(filters=64, kernel_size=(2,2), activation='relu')(out)
    out = MaxPooling2D(pool_size=(2,2))(out)
    out = Flatten()(out)
    out = Dense(n_outputs, activation='softmax')(out)
    model = Model(inputs=inp, outputs=out)
    model.compile(loss='binary_crossentropy', optimizer='adam')
    model.summary()
    

    优点



    缺点



    TF1示例
    # Input
    tf_in = tf.placeholder(shape=[None, height, width, n_channels], dtype=tf.float32)
    
    # 1st conv and max pool
    conv1 = tf.Variable(tf.initializers.glorot_uniform()([2,2,3,32]))
    tf_out = tf.nn.conv2d(tf_in, filters=conv1, strides=[1,1,1,1], padding='SAME') # 64,64
    tf_out = tf.nn.max_pool2d(tf_out, ksize=[2,2], strides=[1,2,2,1], padding='SAME') # 32,32
    
    # 2nd conv and max pool
    conv2 = tf.Variable(tf.initializers.glorot_uniform()([2,2,32,64]))
    tf_out = tf.nn.conv2d(tf_out, filters=conv2, strides=[1,1,1,1], padding='SAME') # 32, 32
    tf_out = tf.nn.max_pool2d(tf_out, ksize=[2,2], strides=[1,2,2,1], padding='SAME') # 16, 16
    tf_out = tf.reshape(tf_out, [-1, 16*16*64])
    
    # Dense layer
    dense = conv1 = tf.Variable(tf.initializers.glorot_uniform()([16*16*64, n_outputs]))
    tf_out = tf.matmul(tf_out, dense)
    

    优点



    缺点



    注意事项和陷阱

    在这里,我将列出使用TF时需要注意的几件事(根据我的经验)。

    TF1-忘记提供所有相关的占位符以计算结果
    tf_a = tf.placeholder(dtype=tf.float32)
    tf_b = tf.placeholder(dtype=tf.float32)
    tf_c = tf.add(tf_a, tf.math.multiply(tf_b, 2.0))
    
    with tf.Session() as sess:
        c = sess.run(tf_c, feed_dict={tf_a: 5.0})
        print(c)
    



    出现错误的原因是,您尚未向tf_b输入值。因此,请确保将所有依赖项占位符的值都提供给,以计算结果。

    TF1-务必非常小心数据类型
    tf_a = tf.placeholder(dtype=tf.int32)
    tf_b = tf.placeholder(dtype=tf.float32)
    tf_c = tf.add(tf_a, tf.math.multiply(tf_b, 2.0))
    
    with tf.Session() as sess:
        c = sess.run(tf_c, feed_dict={tf_a: 5, tf_b: 2.0})
        print(c)
    



    您能发现错误吗?这是因为在将数据类型传递给操作时必须匹配数据类型。否则,请使用tf.cast()操作将您的数据类型转换为兼容的数据类型。

    Keras-了解每一层期望的输入形状
    model = Sequential()
    model.add(Conv2D(filters=32, kernel_size=(2,2),
    activation='relu',input_shape=(height, width)))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Conv2D(filters=64, kernel_size=(2,2), activation='relu'))
    model.add(MaxPooling2D(pool_size=(2,2)))
    model.add(Flatten())
    model.add(Dense(n_outputs, activation='softmax'))
    model.compile(loss='binary_crossentropy', optimizer='adam')
    



    在此,您已定义了输入形状[None, height, width](添加批次尺寸时)。但是Conv2D需要4D输入[None, height, width, n_channels]。因此,您会收到上述错误。一些通常被误解/容易出错的层是,
  • Conv2D层-需要4D输入[None, height, width, n_channels]。要更详细地了解卷积层/操作,请查看此answer
  • LSTM层-需要3D输入[None, timesteps, n_dim]
  • ConvLSTM2D层-需要5D输入[None, timesteps, height, width, n_channels]
  • Concatenate层-除轴外,在所有其他维度上串联的数据必须是相同的

  • Keras-在fit()期间输入错误的输入/输出形状
    height=64
    width = 64
    n_channels = 3
    n_outputs = 10
    
    Xtrain = np.random.normal(size=(500, height, width, 1))
    Ytrain = np.random.choice([0,1], size=(500, n_outputs))
    
    # Build the model
    
    # fit network
    model.fit(Xtrain, Ytrain, epochs=10, batch_size=32, verbose=0)
    



    你应该知道这一点。当我们应该输入[batch size, height, width, 1]输入时,我们正在输入[batch size, height, width, 3]形状的输入。

    TF1和TF2之间的性能差异

    这已经在here讨论中了。因此,我不会重复其中的内容。

    我希望我能谈论但不能的事情

    我将留下一些链接以供进一步阅读。
  • tf.data.Dataset
  • tf.RaggedTensor
  • 关于python - TensorFlow和Keras上的引物: The past (TF1) the present (TF2),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/59112527/

    10-12 16:39