陌路茶色/

TensorFlow2使用手册

基础部分

1.如果模型训练过程中被中断了,那如何继续训练?如果模型不想继续训练了,就killed掉了,是否还可以使用训练的结果进行预测?
使用tf.keras.callbacks.ModelCheckpoint,在callbacks中添加该函数
一般使用如下:

checkpoint_filepath = '/tmp/checkpoint'
model_checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath=checkpoint_filepath,
    save_weights_only=True,
    monitor='val_acc',
    mode='max',
    save_best_only=True)

上述只会保存一个ckpt,会根据val_acc来判断和之前最好的比较,是否覆盖(filepath写死才会发生覆盖)。filepath可以写成{}的方式,这样就不会出现覆盖的问题,如下:

args.checkpoint_dir=os.path.join(project_dir,'log/checkpoint/'+args.model_name)
args.checkpoint_prefix = os.path.join(args.checkpoint_dir, "ckpt_{epoch}")

训练生成的ckpt大概是这样的:
image.png
训练过程被中断后,继续训练,或者是使用训练的模型进行evaluate:
因为只保存了weights,需要先构造好model后,使用如下方式【这里会出现一个问题,那么多ckpt,应该选择哪一个?】:

# The model weights (that are considered the best) are loaded into the model.
model.load_weights(checkpoint_filepath)

官网上给出的是这样的结果,说会载入最优的(我理解应该是最近的?),不过我也在一些例子上看到如下写法

latest = tf.train.latest_checkpoint(checkpoint_dir)
model.load_weights(latest)

2.tensorflow2模型如何保存,tensorflow2模型的保存方式有哪些,这些具体怎么理解,checkpoint,save_model等
3.model.fit默认是按照一个epoch进行val的,那如何按step来保存模型呢
4.如何使用tensorboard来查看模型的参数训练过程,以及对模型调试优化的指导
5.tensorflow训练的时候为什么会被killed,为什么训练过程中内存会不断的增大
因为内存不足导致的killed问题,我的这个问题是因为dataset.cache造成的
显存不足是会打印outofmemory
6.tensorflow中的graph怎么理解,operator怎么理解
7.tf中的verbose
日志显示情况
8.tf做predict的时候,如果只用到模型某一个部分的输出,那怎么样只喂进去该部分需要的特征?如何取中间结果,又如何将中间结果喂进去?
如果只用模型的一部分输出,而该输出只需要喂入一部分输入特征,我的解决方案是其它输入特征补0即可。取中间层的结果也非常容易。
如果在做predict时,修改了模型,因此只需要原始模型的部分层的参数,如何做呢?
直接获取对应层的参数来初始化新生成的层,或者构建一个新的模型,而该模型只载入原始模型的部分参数即可,待尝试。
我遇到的场景是这样的:我想从模型的中间层输入tensor,取模型的最后输出,我尝试如下使用:

model.load_weights(latest)
predict_model=tf.keras.Model(inputs=model.get_layer('merge_nn_relu_0').input,outputs=model.outputs)

结果报错,显示Model的input必须是tf.keras.Input,不能是某个非输入层的输出。
这样我只能构建一个新的模型,然后将对应的参数拷贝到这个新的模型中:

sub_model=sub_nn_model(FLAGS)
nn_model_layer_names=set(map(lambda x:x.name,model.layers))
sub_nn_model_layer_names=set(map(lambda x:x.name,sub_model.layers))
common_layer_names=nn_model_layer_names & sub_nn_model_layer_names
for layer_name in common_layer_names:
    temp=model.get_layer(layer_name).get_weights()
    sub_model.get_layer(layer_name).set_weights(temp)

下面这种方法就是完全的模型copy,不适合。

for a, b in zip(model_a.variables, model_b.variables):
  a.assign(b)

能够获取到中间层的输出,但是获取不到op的输出,这也是经常能见到一个op通常都会对应一个layer。

9.如何创建一个tensor,tensor的种类,对tensor的理解
https://www.tensorflow.org/guide/tensor
常见生成tensor的函数:

# constant
rank_2_tensor = tf.constant([[1, 2],
                             [3, 4],
                             [5, 6]], dtype=tf.float16)
rank_4_tensor = tf.zeros([3, 2, 4, 5])

tensor支持单/多轴索引/切片:

rank_1_tensor = tf.constant([0, 1, 1, 2, 3, 5, 8, 13, 21, 34])
print("Before 4:", rank_1_tensor[:4].numpy())

reshape函数改变张量的形状,重构速度很快,资源消耗很低,因为不需要复制底层数据。交换轴需要使用tf.transpose。
Tensor.dtype属性可以检查tf.Tensor的数据类型,数据类型也可以使用tf.cast来转换。
通过使用np.array()或tensor.numpy方法将张量转为numpy数组:

np.array(rank_2_tensor)
rank_2_tensor.numpy()
tf.convert_to_tensor可以将numpy转为tensor【这个函数还可以接受其他类型的元素】
arg = tf.convert_to_tensor(np.array([[1.0, 2.0], [3.0, 4.0]], dtype=np.float32))

10.变量(tf.Variable)的理解,与tensor的区别
https://www.tensorflow.org/guide/variable
创建变量需要提供一个初始值,如下所示:

my_tensor = tf.constant([[1.0, 2.0], [3.0, 4.0]])
my_variable = tf.Variable(my_tensor)
bool_variable = tf.Variable([False, False, False, True])

变量和张量定义方式和操作行为类似,也有dtype,shape,numpy功能:

print("Shape: ",my_variable.shape)
print("DType: ",my_variable.dtype)
print("As NumPy: ", my_variable.numpy)

大部分张量运算在变量上也可能按预期运行,不过变量无法重构形状
两个变量可以使用相同的名称???【变量和层应该是两个不同的概念,当我在一个模型中的不同层使用相同的name是,模型就会 报错:All layer names should be unique】
变量中的值可以使用assign被重新分配,但是需要与之前shape相同,如下

a=tf.Variable([2,3])
print(a)
a.assign([4,5])
print(a)
####
#<tf.Variable 'Variable:0' shape=(2,) dtype=int32, numpy=array([2, 3], dtype=int32)>
#<tf.Variable 'Variable:0' shape=(2,) dtype=int32, numpy=array([4, 5], dtype=int32)>

可以用某个变量来初始化另外一个变量,这两个变量之间不共享内存:

a=tf.Variable([2,3],name='a')
b=tf.Variable(a,name='b')
a.assign([5,6])
print(a)
print(b)
####
#<tf.Variable 'a:0' shape=(2,) dtype=int32, numpy=array([5, 6], dtype=int32)>
#<tf.Variable 'b:0' shape=(2,) dtype=int32, numpy=array([2, 3], dtype=int32)>

为了提高性能,tf会尝试将张量和变量放在与其dtype兼容最快的设备上,即大部分都会放置在GPU上,如果要手动设置需要进行指定,不如多GPU工作,我希望变量只有一个副本【即:多GPU模式下,模型中的变量会在每个GPU上都有一个副本,会很占内存???】,可以这样做:

with tf.device('CPU:0'):
  a = tf.Variable([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
  b = tf.Variable([[1.0, 2.0, 3.0]])

with tf.device('GPU:0'):
  # Element-wise multiply
  k = a * b

print(k)

上述,将一个变量放置在CPU上,GPU上做op,那op完后就会去更新变量,这样就会出现数据复制问题。
【这个我有个疑问,如果是多GPU,怎么还需要指定在哪一个GPU上执行op操作呢,我理解是可以去掉with tf.device('GPU:0')的,op会默认在GPU上操作】
11.一些常用的函数
tf.math.argmax:按指定维度取最大值对应的索引
12.如何自定义梯度求导,自定义 end2end train model
主要解释training loop过程:

  • We open a for loop that iterates over epochs
  • For each epoch, we open a for loop that iterates over the dataset, in batches
  • For each batch, we open a GradientTape() scope
  • Inside this scope, we call the model (forward pass) and compute the loss
  • Outside the scope, we retrieve the gradients of the weights of the model with regard to the loss
  • Finally, we use the optimizer to update the weights of the model based on the gradients
# Instantiate an optimizer to train the model.
optimizer = keras.optimizers.SGD(learning_rate=1e-3)
# Instantiate a loss function.
loss_fn = keras.losses.SparseCategoricalCrossentropy(from_logits=True)

# Prepare the metrics.
train_acc_metric = keras.metrics.SparseCategoricalAccuracy()
val_acc_metric = keras.metrics.SparseCategoricalAccuracy()

epochs = 2
for epoch in range(epochs):
    print("\nStart of epoch %d" % (epoch,))
    start_time = time.time()

    # Iterate over the batches of the dataset.
    for step, (x_batch_train, y_batch_train) in enumerate(train_dataset):
        with tf.GradientTape() as tape:
            logits = model(x_batch_train, training=True)
            loss_value = loss_fn(y_batch_train, logits)
        grads = tape.gradient(loss_value, model.trainable_weights)
        optimizer.apply_gradients(zip(grads, model.trainable_weights))

        # Update training metric.
        train_acc_metric.update_state(y_batch_train, logits)

        # Log every 200 batches.
        if step % 200 == 0:
            print(
                "Training loss (for one batch) at step %d: %.4f"
                % (step, float(loss_value))
            )
            print("Seen so far: %d samples" % ((step + 1) * 64))

    # Display metrics at the end of each epoch.
    train_acc = train_acc_metric.result()
    print("Training acc over epoch: %.4f" % (float(train_acc),))

    # Reset training metrics at the end of each epoch
    train_acc_metric.reset_states()

    # Run a validation loop at the end of each epoch.
    for x_batch_val, y_batch_val in val_dataset:
        val_logits = model(x_batch_val, training=False)
        # Update val metrics
        val_acc_metric.update_state(y_batch_val, val_logits)
    val_acc = val_acc_metric.result()
    val_acc_metric.reset_states()
    print("Validation acc: %.4f" % (float(val_acc),))
    print("Time taken: %.2fs" % (time.time() - start_time))

使用tape确保tensor可以在scope中被traced
tape.gradient(target,sources):用target对sources求导,api中对应的是target和sources都可以是list。返回的值是和sources中一一对应的
optimizer.apply_gradients方法由来更新变量,传入梯度值和对应的变量。
metric函数有三个方法,update_state方法用来更新metric,reset_states方法用来重置metric参数,result方法用来求解metric。
【如果想让权重也参与到loss中,上面的代码该如何改写,又该如何理解:
loss=常规损失函数+某一权重取正则化的的结果
比如说上面的loss改写为:
loss_value = loss_fn(y_batch_train, logits)+tf.nn.l2_loss(w)
这样对w的更新会有两部分参与,一部分是loss_fn的,一部分是l2正则的作用
tf.nn.l2_loss:Computes half the L2 norm of a tensor without the sqrt
output = sum(t ** 2) / 2
这个效果就是不要让w的值过大,w可以是某层的参数,也可以是embedding。

13.微分的理解
https://www.tensorflow.org/guide/autodiff
结合12和该地址看。
14.梯度消失和梯度爆炸该如何解决
15.有时间看一下各种optimizer,尤其是ftrl,到底是解决什么问题?
16.查看model权重,layer权重
model.weights
layer.weights
17.embedding_lookup的时候怎么样实现如果找不到取默认的结果
18.如何定义层
19.tf.function
参考https://www.tensorflow.org/guide/intro_to_graphs,https://www.tensorflow.org/guide/function , 一般的Model都在tf.function中,这个应该是在自定义的函数中使用。

留下一条评论

暂无评论