tensorflow 1.x 到 tensorflow 2.x

一、tensorflow 1.x 和 tensorflow 2.x

  • 1、在TensorFlow 2.x 中,仍然可以运行未经修改的1.x代码
    import tensorflow.compat.v1 as tf tf.disable_v2_behavior()
  • 2、使用tf.compat.v1端点来访问占位符、会话、集合

二、tensorflow1.x 转为 tensorflow2.x

2.1 tf.Session.run

  • feed_dict和tf.placeholder变成函数参数
  • fetches变成函数的返回值

可以使用标准Python工具(如pdb)逐步调试该函数。如果还想继续使用Session,可以添加一个tf.function装饰器,使其在图形模型下高效运行。

2.2 跟踪变量和损失

使用tf.Variable代替tf.get_variable,每个variable_scope可转换成Python对象:

tf.keras.layers.layer

tf.keras.Model

tf.Module

如果需要聚合变量列表(如tf.Graph.get_collection(tf.GraphKeys.VARIABLES)),请使用Layer和Model对象的.variables.trainable_variables属性。

这些Layer和Model类实现了几个其他属性,无需全局几何。他们的.losses属性可以替代使用tf.GraphKeys.LOSSES集合。

2.3 训练循环

使用适用的高级API,最好是tf.keras.Model.fit建立自己的训练循环。

但是这些高级函数容易遗漏一些低级细节,(例如,它们会自动收集正则化损失,并在调用模型时设置training=True参数)。如果需要修改训练细节,建议使用自定义训练。

@tf.function
def train_step(inputs, labels):
    with tf.GradientTape() as tape:
        predictions = model(inputs)
        loss = loss_fn(labels, predictions)
    gradients = tape.gradient(loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

    mean_loss = train_loss(loss)  
    train_accuracy(labels, predictions)
    return predictions, mean_loss

@tf.function
def test_step(inputs, labels):
    with tf.GradientTape() as tape:
        predictions = model(inputs)
        t_loss = loss_fn(labels, predictions)
    gradients = tape.gradient(t_loss, model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

三、转换模型

3.1 安装环境

from __fucture__ import absolute_import, division, print_function 
import tensorflow as tf \# pip install –q tensorflow==2.0.0-alpha0 
import tensorflow_datasets as tfds

3.2 低阶变量和执行

低级API使用的示例包括:

  • 使用变量范围来控制重用

  • 使用tf.get_variable创建变量

  • 明确地访问集合

  • 使用以下方式隐式访问集合:

  • tf.global_variables

  • tf.losses.get_regularization_loss

  • 使用tf.placeholder设置图形输入

  • 使用session.run执行图

  • 手动初始化变量

TensorFlow 1.x代码:

in_a = tf.placeholder(dtype=tf.float32, shape=(2)) 
in_b = tf.placeholder(dtype=tf.float32, shape=(2)) 

def forward(x): 
    with tf.variable_scope(‘matmul’, resuse=tf.AUTO_RESUE): 
        W = tf.get_variable(‘W’, initializer=tf.ones(shape=(2,2)), regularizer=tf.contrib.layers.l2_regularizer(0.04)) 
        b = tf.get_variable(‘b’, initializer=tf.zeros(shape=(2))) 
        return x \* train_data + b 

out_a = model(in_a) 
out_b = model(in_b) 
reg_loss = tf.losses.get_regularization_loss(scope=’matmul’) 

with tf.Session() as sess: 
    sess.run(tf.global_variables_initializer()) 
    outs = sess.run([out_a, out_b, reg_loss], feed_dict={in_a: [1, 0], in_b: [0, 1]})

TensorFlow 2.x:

  • 变量是本地Python对象

  • 前向函数依然定义了计算

  • sess.run调用被替换为forward的调用

  • 可以添加可选的tf.function装饰器以提高性能

  • 正则化是手动计算的,不设计任何全局集合

  • 没有sessions和placeholders

W = tf.Variable(tf.ones(shape=(2, 2)), name=”W”) 
b = tf.Variable(tf.zeros(shape=(2)), name=”b”) 

@tf.function 
def forward(x): 
    return W \* x + b out_a = forward([1, 0]) print(out_a) 

out_b = forward([0, 1]) 
regularizer = tf.keras.regularizers.l2(0.02) 
reg_loss = regularizer(W)                                                                                   

3.3 tf.layers 模型

转换之前:

def model(x, training, scope=’model’): 
    with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
        x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu, kernel_regularizer = tf.contrib.layers.l2_regularizer(0.04)) 
        x = tf.layers.max_pooling2d(x, (2, 2), 1) 
        x = tf.layers.flatten(x) 
        x = tf.layers.dropout(x, 0.1, training=training) 
        x = tf.layers.dense(x, 64, activation=tf.nn.relu) 
        x = tf.layers.batch_normalization(x,training=training) 
        x = tf.layers.dense(x, 10, activation=tf.nn.softmax) 
        return x 

train_out = model(train_data, training=True) 
test_out = model(test_data, training=False)

转换之后:

model = tf.keras.Sequential([ 
    tf.keras.layers.Conv2D(32, 3, activation=’relu’, kernel_regularizer=tf.keras.regularizers.l2(0.02), input_shape=(28, 28, 1)), tf.keras.layers.MaxPooling2D(), 
    tf.keras.layers.Flatten(), 
    tf.keras.layers.Dropout(0.1), 
    tf.keras.layers.Dense(64, activation=’relu’), 
    tf.keras.lyaers.BatchNormalization(), 
    tf.keras.layers.Dense(10, activation=’softmax’) 
]) 

train_data = tf.ones(shape=(1, 28, 28, 1)) 
test_data = tf.ones(shape=(1, 28, 28, 1)) 
train_out = model(train_data, training=True) 
print(train_out) 
test_out = model(test_data, training= False) 
print(test_out) # 这里是所有可训练的变量 
print(len(model.trainable_variables) # 这里是正则化损失 print(model.losses) 
  • 简单的层堆栈可以整齐地放入tf.keras.Sequence中(对于更复杂的模型,请参见自定义层和模型,以及函数API

  • 模型跟踪变量和正则化损失

  • 转换是一对一的,因为它是从tf.layerstf.keras.layers直接映射的。

大多数参数保持不变,但注意区别:

  • 训练参数在运行时由模型传递给每个层

  • 原来模型函数的第一个参数(input x)消失,这是因为层将构建模型与调用模型分开了。

同时也要注意:

  • 如果你使用tf.contrib的初始化器的正则化器,那么它们的参数变化会比其他变量更多。

  • 代码不再写入集合,像tf.losses.get_regularization_loss将不再返回值,这可能会破坏训练循环。

3.4 tf.layers 和混合变量

现存的代码通常将较低级别的tensorflow 1.x变量和操作与较高级的tf.layers混合。

转换前:

def model(x, training, scope='model'):
    with tf.variable_scope(scope, reuse=tf.AUTO_REUSE): 
        W = tf.get_variable("W", dtype=tf.float32, 
                            initializer=tf.ones(shape=x.shape), 
                            regularizer=tf.contrib.layers.l2_regularizer(0.04), 
                            trainable=True) 
        if training:  
            x = x + W   
        else: 
            x = x + W \* 0.5
        x = tf.layers.conv2d(x, 32, 3, activation=tf.nn.relu) 
        x = tf.layers.max_pooling2d(x, (2, 2), 1) 
        x = tf.layers.flatten(x)  
        return x  

        train_out = model(train_data, training=True)  
        test_out = model(test_data, training=False)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

转换后:

# 创建自定义图层 
class CustomLayer(tf.keras.layers.Layer): 
    def __init__(self, *args, **kwargs):    # 在init中收集层参数
        super(CustomLayer, self).__init__(*args, **kwargs) 

    def build(self, input_shape):           # 在build中构建变量
        self.w = self.add_weight(shape=input_shape[1:], 
                                dtype=tf.float32, 
                                initializer=tf.keras.initializers.ones(), 
                                regularizer=tf.keras.regularizers.l2(0.02), 
                                trainable=True) # 调用方法有时会在图形模式下使用,训练会变成一个张量 
    
    @tf.function 
    def call(self, inputs, training=None):    # 在call中执行计算并返回结果
        if training: 
            return inputs + self.w 
        else: 
            return inputs + self.w * 0.5 

custom_layer = CustomLayer() 
print(custom_layer([1]).numpy()) 
print(custom_layer([1], training=True).numpy()) 

train_data = tf.ones(shape=(1, 28, 28, 1)) 
test_data = tf.ones(shape=(1, 28, 18, 1)) # 构建包含自定义层的模型 

model = tf.keras.Sequential([ 
    CustomLayer(input_shape=(28, 28, 1)), 
    tf.keras.layers.Conv2D(32, 3, activation=’relu’), 
    tf.keras.layers.MaxPooling2D(), 
    tf.keras.layers.Flatten() 
    ]) 
train_out = model(train_data, training=True) 
test_out = model(test_data, trainging=False)                                                                                                                                                                                         

注:

  • 子类化的Keras模型和层需要在v1图(无自动控制依赖关系)和eager模型是运行

  • 将call()封装在tf.function()中以获取自动图和自动控制依赖项

  • 调用时需要一个训练参数(tf.Tensor或Python布尔值)

  • 使用self.add_weight()在构造函数或def build()中创建模型变量

  • 在build中,可以访问数据的形状,因此可以创建具有匹配形状的权重

  • 使用tf.keras.layers.Layser.add_weight可以让Keras跟踪变量和正则化损失

  • 不要将tf.Tensor保存在对象中

  • 使用tf.Variables作为状态,它们始终可用于两个上下文

四、训练

有多种方式将数据馈送给tf.keras模型,可以是Python生成器和Numpy数据作为输入。

将数据馈送给模型的推荐方法是使用tf.data包,如果仍在使用tf.queue,则仅支持作为数据结构,而不是数据管道。

4.1 Datasets的使用

TensorFlow数据集包(tfds)包含用于将预定义数据集加载为tf.data.Dataset对象的使用程序。使用tfds加载MNIST数据集:

datasets, ds_info = tfds.load(name=’mnist’, with_info=True, as_supervised=True) 
mnist_train, mnist_test = datasets[‘train’], datasets[‘test’] 

然后对数据进行处理,缩放、打乱样本顺序以及做image和label,为训练准备数据:

BUFFER_SIZE = 10 # 实际代码中使用更大的值 
BATCH_SIZE = 64 
NUM_EPOCHS = 5 

def scale(image, label): 
    image = tf.cast(image, tf.float32) 
    image /= 255 
    return image, label 

train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE).take(5) 
test_data = mnist_test.map(scale).batch(BATCH_SIZE).take(5) 
STEPS_PER_EPOCH = 5 # 使示例保持简短,仅返回5个批次 
train_data = train_data.take(STEPS_PER_EPOCH) 
test_data = test_data.take(STEPS_PER_EPOCH) 
image_batch, label_batch = next(iter(train_data)) 

4.2 keras内置的fit、evaluate和predict循环训练

如果不需要对训练过程进行低级别的控制,建议使用Keras内置的fit、evaluate和predict方法,这些方法提供了一个统一的接口来训练模型。

model = tf.keras.Sequential([ 
            tf.keras.layers.Conv2D(32, 3, activation=’relu’, kernel_regularizer=tf.keras.regularizers.l2(0.02), input_shape=(28, 28 ,1)), tf.keras.layers.MaxPooling2D(), 
            tf.keras.layers.Flatten(), 
            tf.keras.layers.Dropout(0.1), 
            tf.keras.layers.Dense(64, activation=’relu’), 
            tf.keras.layers.BatchNormalization(), 
            tf.keras.layers.Dense(10, activation=’softmax’) ]) 

# 模型是没有自定义图层的完整模型 
model.compile(optimizer=’adam’, loss=’spare_categorical_crossentropy’, metrics=[‘accuracy’]) 
model.fit(train_data, epochs=NUM_EPOCHS) 
loss, acc = model.evaluate(test_data) 
print(“Loss {}, Accuracy {}.format(loss, acc)) 
  • Keras内置的fit、evaluate和predict的优点:

  • 它们接受Numpy数组、Python生成器和tf.data.Datasets

  • 它们自动应用正则化和激活损失

  • 它们支持用于多设备训练的tf.distribute

  • 它们支持任意的callables作为损失和指标

  • 它们支持回调,如tf.keras.callbacks.TensorBoard和自定义回调

  • 它们具有高性能,可自动使用TensorFlow图形

4.3 编写自己的训练循环

如果Keras模型的训练步骤适合,但需要在该步骤之外进行更多的控制,可以在数据迭代循环中使用tf.keras.model.train_on_batch

:许多东西可以作为tf.keras.Callback实现

此方法具有上一节中提到的方法的许多优点,另外还允许用户控制外循环。

使用tf.keras.model.test_on_batchtf.keras.Model.evaluate来检查训练期间的性能

以下代码是接着4.2节代码继续训练的:

# 模型是没有自定义图层的完整模型 
model.compile(optimizer=’adam’, loss=’sparse_categorical_crossentropy’, metrics=[‘accuracy’]) 
metrics_names = model.metrics_names 
for epoch in range(NUM_EPOCHS): 
    # 重置指标 
    model.reset_metrics() 

for image_batch, labels_batch in train_data: 
    result = model.train_on_batch(image_batch, label_batch) 
print(“train:,{}: {:.3f}.format(metrics_names[0], result[0]),{}: {:.3f}.format(metrics_names[1], result[1])) 

for image_batch, label_batch in test_data: 
    result = model.test_on_batch(image_batch, label_batch, reset_metrics=False) 
print(“\\neval:,{}: {:.3f}.format(metrics_names[0], result[0]),{}: {:.3f}.format(metrics_names[1], result[1]))                                                                                                                                                                                                                                                                                                                                                                        

4.4 自定义训练步骤

如果需要更多的灵活性和控制,可以通过自定义训练循环来实现,这有以下三个步骤:

  • 迭代Python生成器或tf.data.Dataset以获取样本数据

  • 使用tf.GradientTape求梯度

  • 使用tf.keras.optimizer将权重更新应用于模型

model = tf.keras.Sequential([ 
    tf.keras.layers.Conv2D(32, 3, activation=’relu’, kernel_regularizer=tf.keras.regularizer.l2(0.02), 
    tf.keras.layers.MaxPooling2D(), 
    tf.keras.layers.Flatten(), 
    tf.keras.layers.Dropout(0.1), 
    tf.keras.layers.Dense(64, activation=’relu’), 
    tf.keras.layers.BatchNormalization(), 
    tf.keras.layers.Dense(10, activation=’softmax’) ]) 

optimizer = tf.keras.optimizers.Adam(0.001) 
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy() 

@tf.function 
def train_step(inputs, labels): 
    with tf.GradientTape() as tape: 
        predictions = model(inputs, training=True) 
        regularization_loss = tf.math.add_n(model.losses) 
        pred_loss = loss_fn(labels, predictions)
        total_loss = pred_loss + regularization_loss 
    gradients = tape.gradient(total_loss, model.trainable_variables) 
    optimizer.apply_gradients(zip(gradients, model.trainable_variables)) 

for epoch in range(NUM_EPOCHS): 
    for inputs, labels in train_data: 
        train_step(inputs, labels)

    print(“Finished epoch”, epoch) 

  • 始终在子类层和模型的调用方法中包含一个训练参数

  • 确保在正确设置训练参数的情况下调用模型

  • 在对一批数据运行模型之前,模型变量可能不存在

  • 需要手动处理模型的正则化损失等事情

4.5 新型指标

在TensorFlow2.0中,metrics是对象,Metrics对象在eager和tf.functions中运行:

  • update_state()– 添加新的观察结果

  • result() – 给定观察值,获取metrics的当前结果

  • reset_states() – 清除所有观察值

对象本身是可调用的,与update_state一样,调用新观察更新状态,并返回metrics的新结果。

下面的代码使用metrics来跟踪自定义训练循环中观察到的平均损失:

# 创建metrics 
loss_metric = tf.keras.metrics.Mean(name=’train_loss’) 
accuracy_metrics = tf.keras.metrics.SparseCategoricalAccuracy(name=’train_accuracy’) 

@tf.function 
def train_step(inputs, labels): 
    with tf.GradientTape() as tape: 
        predictions = model(inputs, training=True) 
        regularization_loss = tf.math.add_n(model.losses) 
        pred_loss = loss_fn(labels, predictions) 
        total_loss = pred_loss + regularization_loss 

    gradients = tape.gradient(total_loss, model.trainable_variables) 
    optimizer.apply_gradients(zip(gradients, model.trainable_variables)) 

    # 更新metrics 
    loss_metrics.update_state(total_loss) 
    accuracy_metrics.update_state(labels, predictions) 

for epoch in range(NUM_EPOCHS):
    # 重置metrics 
    loss_metric.reset_states() 
    accuracy_metric.reset_states() 
    for inputs, labels in train_data: 
        train_step(inputs, labels) 

    # 获取metric结果 
    mean_loss = loss_metric.result() 
    mean_accuracy = accuracy_metric.result() 

    print(“Epoch:, epoch) 
    print(“ loss: {:.3f}.format(mean_loss)) 
    print(“accuracy:: {:.3f}.format(mean_accuracy)) 

五、保存模型和加载模型

5.1 Checkpoint

加载旧式的基于名称的检查点,代码转换过程可能会导致变量名的更改,但是有一些变通的方法。

最简单的方法是将新模型的名称与检查点的名称对齐:

  • 变量仍然都有你可以设置的名称参数。

  • Keras模型还采用名称参数,并将其设置为变量的前缀。

  • tf.name_scope函数可用于设置变量名称前缀,这与tf.variable_scope不同,它只影响名称,不跟踪变量和重用。

import tensorflow as tf 

a= tf.
b= tf.
result = a+b

init_op = tf.initialize_all_varibales()

# 定义Saver类对象用于保存模型
saver = tf.train.Saver()

with tf.Session as sess:
	sess.run(init_op)
	saver.save(sess,'./model.ckpt')

5.2 Keras模型保存模型

def make_model(): 
    rerurn tf.keras.Sequential([ tf.keras.layers.Conv2D(32, 3, activation=’relu’, kernel_regularizer=tf.keras.regularizers.l2(0.02), inut_shape=(28, 28, 1)), 
        tf.keras.layers.MaxPooling2D(), 
        tf.keras.layers.Flatten(), 
        tf.keras.layers.Dropout(0.1), 
        tf.keras.layers.Dense(64, activation=’relu’), 
        tf.keras.layers.BatchNormalization(), 
        tf.keras.layers.Dense(10, activation=’softmax’) ]) 

model = make_model() 
model.compile(optimizer=’adam’, loss=’sparse_categorical_crossentropy’, metrics=[‘accuracy’]) 
model.fit(x=train_x, y=train_y, epochs=10, batch_size=100, validation_data=(test_x, test_y)
model.save('./model.h5')                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       

使用keras.models.load_model()加载模型。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值