边境的悍匪—机器学习实战:第十二章 使用TensorFlow自定义模型和训练

第十二章 使用TensorFlow自定义模型和训练


前言

我们在训练或者是构建一个神经网络的时候,在一些特殊情况出现时,我们可能会需要自定义一个神经网络的组件,例如:损失函数、激活函数、指标或者是层、模型,虽然这往往是一些极少出现的情况,但我们还是需要学会如何使用。本章节大部分为应用与实操,很少有需要理解的理论部分,就让我们一起操作起来吧。


一、思维导图

在这里插入图片描述

二、主要内容

1、TensorFlow快速浏览

TensorFlow是由Google Brain团队开发的用于数值计算的强大的库,非常适合大规模的机器学习。并且TensorrFlow为机器学习提供了tf.keras、数据加载、数据处理在内的多个核心功能,和一个完整丰富的生态。TensorFlow提供的keras和一些高级API已经可以完成95%的业务,剩下的5%需要我们自定义一些组件来完成。

2、像NumPy一样使用TensorFlow

  1. 操作和张量
    TensorFlow中的所有API都是围绕这张量来完成的,并且你可以在TensorFlow中找到所有的基本数学运算来操作这些张量。
  2. 张量和NumPy
    我们可以使用NumPy创建一个TF张量,同样反过来使用TensorFlow创建一个NumPy数组也是可以的。唯一需要注意的就是NumPy中的精度是64而TensorFlow中精度为32就已经足够了。
  3. 类型转换
    在TensorFlow中类型的转换可能会影响性能并且会出现类型转换的错误。所以TensorFlow并不支持类型的自动转换。
  4. 变量
    上文所提到的所有张量都是不可变的,但是我们在训练神经网络时需要修改连接权重,这个时候我们就需要用到tf.Variable,它的值可以修改的。不过如果我们只是需要修改连接的权重,那么可以直接使用提供的API来完成。
  5. 其他数据类型
    除了刚刚提到的数据类型,TensorFlow还支持:稀疏张量、张量数组、不规则张量、字符串张量、集合、队列。

3、定制模型和训练算法

  1. 自定义损失函数
    如果你感觉TF提供的损失函数不足以满足你的需求时,你可以自定义一个损失函数,并像使用原始损失函数一样使用自定义的损失函数。
  2. 保存和加载包含自定义组件的模型
    当模型使用了自定义的损失函数,那么在加载模型的时候需要手动把损失函数映射到对象中。如果你的损失函数需要设置阀值,那么你可以创建一个生成你损失函数的函数作为你的自定义损失函数。但是这种方法不能把阀值在你保存模型时保存下来,如果你需要保存你的阀值,则需要创建一个keras.losses.Loss的子类,并实现get_config方法。
  3. 自定义激活函数、初始化、正则化和约束
    激活函数、初始化、正则化、约束这些组件的自定义与激活函数都是一样的,唯一不同的你需要为激活函数实现call()方法,为初始化、正则化、约束实现__call__()方法。
  4. 自定义指标
    指标和损失函数在概念上不是一回事,但是可以使用定义一个损失函数的方式来定义一个指标。当你定义一个简单的损失函数时,keras会为每个批次调用该函数,然后计算均值。如果我们遇到一个指标不能只是简单的计算均值时就需要实现流式指标。
  5. 自定义层
    如果当你想构建一个比较特殊的神经网络框架时你就需要自定义层。如果只是一个不带任何权重的层,那么值需要讲函数包装在keras.layers.Lambda层中就行。如果需要给你自定义的层赋予权重,那么就需要创建一个keras.layers.Layer的子类来完成具体的操作。
  6. 自定义模型
    自定义模型很简单,只需要创建一个keras.Model的子类,并在构造函数中创建变量和层,在call()方法中实现你想要执行的操作即可。
  7. 自定义模型基于模型的内部损失和指标
    上文所提到的指标与损失都是基于标签和预测的。但是有的时候我们需要对模型的某一部分定义损失,例如:权重的损失,隐藏层的激活。这个时候我们只需要对指定的部分进行计算然后将计算的结果传给add_loss()就可以实现模型内部的指标与损失计算。
  8. 使用自动微分计算梯度
    我们还可以使用TensorFlow计算任何函数的梯度,甚至还可以阻止反向传播,并编写自己的梯度函数。
  9. 自定义训练循环
    如果你觉得fit()方法已经不足以满足你的需求,你想要模型按照你的方式来操作。那么你还可以自定义训练循环,但是这个方法会导致你的代码更长,并且会暴露出更多的错误,所以不推荐使用,如果是在团队中更加不推荐使用。

4、TensorFlow函数和图

  1. 自动图和跟踪
    TensorFlow一般会通过分析Python源代码的方式来生成图。分析完成之后,他会将所有的操作替换为一个升级版的函数,当调用这个函数时,不需要传任何的参数而是传递一些没有实际值的张量。
  2. TF函数规则
  3. 如果你调用外部库时,那么这些调用不会成为图的一部分,他们只会在跟踪的过程中运行。
  4. 如果你的非TF函数代码有副作用,那不会使得每次调用都会出现副作用,只会使得在跟踪执行时出现。
  5. 你可以使用tf.function包装你的代码成为一个TF函数,但是这样会降低性能和可移植性。
  6. 当你创建了一个TF变量,如果你需要改变她的值那么应该使用assign方法而不是直接等号赋值。
  7. 你的Python源码应该可以用于TF,如果不可以用那么在生成图的过程中会失败或者是首先。
  8. 尽量使用量化而不是循环。

三、课后练习

  1. 如何用一句话形容TensorFlow?它的主要特点是什么?你可以说出其他流行的深度学习库吗?
    TensorFlow是一个用于数值计算的开源库,特别适合大规模机器学习并对其进行微调。它的核心类似于NumPy,但是它还支持GPU、分布式计算、计算图分析和优化功能(具有可移植图格式,允许你在一个环境中训练TensorFlow模型并在另一个环境中运行)。基于反向模式autodiff的优化API,以及一些强大的API,例如tf.keras、tf.data、tf.image、tf.signal等。其他受欢迎的深度学习库包括PyTorch、MXNet、微软的Cognitive工具包、Theano、Caffe2和Chainer。
  2. TensorFlow是否可以简单替代NumPy?两者之间的主要区别是什么?
    尽管TensorFlow提供了NumPy提供的大多数功能,但由于某些原因,它不是简单替代品。首先,函数的名称是并不总是相同的(例如,tf.reduce_sum()与np.sum())。其次,某些函数的行为并不完全相同(例如,tf.transpose()创建一个张量的转置副本,而NumPy的T属性创建一个转置视图,而没有复制任何数据)。最后,NumPy数组是可变的,而TensorFlow张量是不可变的(但如果你需要一个可变对象,则可以使用tf.Variable)
  3. 使用tf.range(10)和tf.constant(np.ara nge(10))是否会得到相同的结果?
    tf.range(10)和tf.constant(np.arange(10))都返回包含整数0到9的一维张量。但是,前者使用32位整数,而后者使用64位整数。实际上,TensorFlow默认为32位,而NumPy默认为64位。
  4. 除了常规张量之外,你还能说出TensorFlow中可用的其他6个数据结构吗?
    除了常规张量之外,TensorFlow还提供其他几种数据结构,包括稀疏张量、张量数组、参差不齐的张量、队列、字符串张量和集合。最后两个实际上表示为常规张量,但是TensorFlow提供了特殊的函数来操作它们(在tf.strings和tf.sets中)。
  5. 可以通过编写函数或继承keras.losses.Loss类来自定义损失函数。你何时会使用哪个方法?
    当你想自定义一个损失函数时,通常可以将其实现为常规Python函数。但是,如果自定义损失函数必须支持某些超参数(或任何其他状态),则应继承keras.losses.Loss类,并实现__init__()方法和call()方法。如果你想和模型一起保存损失函数的超参数,则还必须实现get_config()方法。
  6. 同样,自定义指标可以在函数中定义或者在keras.metrics.Metric子类中定义。你何时会使用哪个方法?
    与自定义损失函数很像,大多数指标可以定义为常规Python函数。但是,如果你希望自定义指标支持某些超参数(或任何其他状态),则应继承keras.metrics.Metric类。此外,如果在整个轮次内计算指标不等同于计算该轮次内所有批量的均值指标(例如,精度和召回率指标),则应继承keras.metrics.Metric类和实现__init__()方法、update_state()方法和result()方法来跟踪每个轮次中运行的指标。你还应该实现reset_states()方法,除非将所有变量都重置为0.0。如果你想把状态与模型一起保存,则还应该实现get_config()方法。
  7. 什么时候应该自定义图而不是自定义模型?
    你应该将模型的内部组件(即层或可重复使用的层块)与模型本身(即要训练的对象)区分开。前者应继承keras.layers.Layer类,而后者应继承keras.models.Model类。
  8. 有哪些示例需要编写你自己的自定义训练循环?
    编写你自己的自定义训练循环是相当高级的,因此只有在确实需要时才应该这样做。Keras提供了多种工具来自定义训练,而不必编写自定义训练循环:回调、自定义正则化、自定义约束、自定义损失等。你应该尽可能使用这些而不是编写自定义训练循环:编写自定义训练循环更容易出错,并且很难重用你编写的自定义代码。但是,在某些情况下有必要编写自定义训练循环——例如,如果你想对神经网络的不同部分使用不同的优化器,例如在“宽与深”论文中。自定义训练循环在调试或试图理解训练的工作原理时也很有用。
  9. 自定义Keras组件可以包含任意Python代码,还是必须转换为TF函数?
    自定义Keras组件应转换为TF函数,这意味着它们应尽可能遵循TF操作并遵守12.4.2节中列出的所有规则。如果你需要在定制组件中包括任意Python代码,可以将其包装在tf.py_function()操作中(但这会降低性能并限制模型的可移植性),或者在创建定制层或模型时设置dynamic=True(或在调用模型的compile()方法时设置
    run_eagerly=True)。
  10. 如果要将函数转换为TF函数,应遵循哪些主要规则?
    文章4.2中已经提到
  11. 你何时需要创建动态Keras模型?你是怎样做的?为什么不让所有模型动态化?
    创建动态Keras模型对于调试很有用,因为它不会将任何自定义组件编译为TF函数,并且你可以使用任何Python调试器来调试代码。如果你想在模型(或训练代码)中包括任意Python代码(包括对外部库的调用),它也很有用。要使模型是动态的,必须在创建模型时设置dynamic=True。或者在调用模型的compile()方法时设置run_eagerly=True。动态创建模型会阻止Keras使用TensorFlow的任何图特征,因此会减低训练和推理的速度,并且你将无法导出计算图,从而限制模型的可移植性。

四、总结

本章内容更加偏向于实操,全文所有代码在文章结尾的git地址中有完整版。这一章主要内容总结一下就是:

  1. 什么是TensortFlow
  2. 使用TensorFlow自定义定组件来处理一些比较特殊的需求
  3. TensorFlow中的图的概念
  4. 使用TensorFlow函数需要注意的规则
    对文章有任何疑惑或者想要和博主一起学机器学习一起进步的朋友们可以添加 群号:666980220。需要机器学习实战电子版或是思维导图的也可以联系我。祝你好运!

项目地址: github

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值