Showing preview only (574K chars total). Download the full file or copy to clipboard to get everything.
Repository: mashangxue/tensorflow2-zh
Branch: master
Commit: a9db13281827
Files: 33
Total size: 436.0 KB
Directory structure:
gitextract_ecdkfdrh/
├── README.md
└── r2/
├── guide/
│ ├── eager.md
│ ├── effective_tf2.md
│ ├── keras/
│ │ ├── functional.md
│ │ ├── overview.md
│ │ └── training_and_evaluation.md
│ └── migration_guide.md
└── tutorials/
├── eager/
│ ├── automatic_differentiation.md
│ ├── basics.md
│ ├── custom_layers.md
│ ├── custom_training.md
│ ├── custom_training_walkthrough.md
│ └── tf_function.md
├── estimators/
│ └── linear.md
├── images/
│ ├── hub_with_keras.md
│ ├── intro_to_cnns.md
│ ├── segmentation.md
│ └── transfer_learning.md
├── keras/
│ ├── basic_classification.md
│ ├── basic_regression.md
│ ├── basic_text_classification.md
│ ├── basic_text_classification_with_tfhub.md
│ ├── feature_columns.md
│ ├── overfit_and_underfit.md
│ └── save_and_restore_models.md
├── quickstart/
│ ├── advanced.md
│ └── beginner.md
└── text/
├── image_captioning.md
├── nmt_with_attention.md
├── text_classification_rnn.md
├── text_generation.md
├── transformer.md
└── word_embeddings.md
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
---
title: tensorflow2官方教程目录导航
categories: tensorflow2官方教程
tags: tensorflow2.0教程
top: 1900
abbrlink: tensorflow/tensorflow2-zh-readme
---
> 最全TensorFlow2.0学习路线 [www.mashangxue123.com](https://www.mashangxue123.com)
# tensorflow2.0 官方教程目录导航
#### Get started with TensorFlow 2.0
#### Effective TensorFlow 2.0(高效的tensorflow 2.0)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-quickstart-beginner.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-quickstart-beginner.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/quickstart/beginner](https://tensorflow.google.cn/beta/tutorials/quickstart/beginner)
> 翻译建议:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/quickstart/beginner.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/quickstart/beginner.md)
#### Migrate from TF 1 to TF 2
#### Convert with the upgrade script
#### Get started for beginners (初学者入门 TensorFlow 2.0)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-quickstart-beginner.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-quickstart-beginner.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/quickstart/beginner](https://tensorflow.google.cn/beta/tutorials/quickstart/beginner)
> 翻译建议:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/quickstart/beginner.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/quickstart/beginner.md)
#### Get started for experts (专家入门TensorFlow 2.0)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-quickstart-advanced.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-quickstart-advanced.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/quickstart/advanced](https://tensorflow.google.cn/beta/tutorials/quickstart/advanced)
> 翻译建议:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/quickstart/beginner.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/quickstart/advanced.md)
## Beginner tutorials
### ML basics
#### Overview
#### Classify images (训练您的第一个神经网络:基本分类)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_classification.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_classification.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/keras/basic_classification](https://tensorflow.google.cn/beta/tutorials/keras/basic_classification)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_classification.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_classification.md)
#### Classify text 使用Keras和TensorFlow Hub对电影评论进行文本分类)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_text_classification_with_tfhub.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_text_classification_with_tfhub.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/keras/basic_text_classification_with_tfhub](https://tensorflow.google.cn/beta/tutorials/keras/basic_text_classification_with_tfhub)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_text_classification_with_tfhub.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_text_classification_with_tfhub.md)
#### Classify structured data (结构化数据分类实战:心脏病预测)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-feature_columns.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-feature_columns.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/keras/feature_columns](https://tensorflow.google.cn/beta/tutorials/keras/feature_columns)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/feature_columns.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/feature_columns.md)
#### Regression (回归项目实战:预测燃油效率 )
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_regression.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_regression.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/keras/basic_regression](https://tensorflow.google.cn/beta/tutorials/keras/basic_regression)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_regression.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_regression.md)
#### Overfitting and underfitting (探索过拟合和欠拟合)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-overfit_and_underfit.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-overfit_and_underfit.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/keras/overfit_and_underfit](https://tensorflow.google.cn/beta/tutorials/keras/overfit_and_underfit)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/overfit_and_underfit.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/overfit_and_underfit.md)
#### Save and restore models (tensorflow2保存和加载模型 )
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-save_and_restore_models.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-save_and_restore_models.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/keras/save_and_restore_models](https://tensorflow.google.cn/beta/tutorials/keras/save_and_restore_models)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/save_and_restore_models.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/save_and_restore_models.md)
### Images
#### Convolutional Neural Networks (使用TensorFlow2.0实现卷积神经网络CNN对MNIST数字分类)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-images-intro_to_cnns.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-images-intro_to_cnns.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/images/save_and_restore_models](https://tensorflow.google.cn/beta/tutorials/images/intro_to_cnns)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/images/intro_to_cnns.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/images/intro_to_cnns.md)
#### Transfer learning with TFHub (基于Keras使用TensorFlow Hub实现迁移学习)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-images-hub_with_keras.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-images-hub_with_keras.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/images/hub_with_keras](https://tensorflow.google.cn/beta/tutorials/images/hub_with_keras)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/images/hub_with_keras.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/images/hub_with_keras.md)
#### Transfer learning with pretrained CNNs (使用预训练的卷积神经网络进行迁移学习)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-images-transfer_learning.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-images-transfer_learning.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/images/transfer_learning](https://tensorflow.google.cn/beta/tutorials/images/transfer_learning)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/images/transfer_learning.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/images/transfer_learning.md)
### Text and sequences
#### Intro to word embeddings (NLP词嵌入Word embedding实战项目)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-word_embeddings.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-word_embeddings.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/text/word_embeddings](https://tensorflow.google.cn/beta/tutorials/text/word_embeddings)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/word_embeddings.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/word_embeddings.md)
#### Classify preprocessed text (文本分类项目实战:电影评论)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_text_classification.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-basic_text_classification.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/keras/basic_text_classification](https://tensorflow.google.cn/beta/tutorials/keras/basic_text_classification)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_text_classification.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/keras/basic_text_classification.md)
#### Classify text with a RNN (使用RNN对文本进行分类实践:电影评论)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-text_classification_rnn.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-text_classification_rnn.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/text/text_classification_rnn](https://tensorflow.google.cn/beta/tutorials/text/text_classification_rnn)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/text_classification_rnn.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/text_classification_rnn.md)
### Estimators
#### Linear models
## Advanced tutorials
### Customization
#### Overview
#### Tensors and operations (tensorflow2.0张量及其操作、numpy兼容、GPU加速)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-basics.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-basics.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/basics](https://tensorflow.google.cn/beta/tutorials/eager/basics)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/basics.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/basics.md)
#### Custom layers (使用Keras自定义层)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_layers.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_layers.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/custom_layers](https://tensorflow.google.cn/beta/tutorials/eager/custom_layers)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_layers.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_layers.md)
#### Automatic differentiation (TF梯度下降法的核心自动微分和梯度带)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-automatic_differentiation.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-automatic_differentiation.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/automatic_differentiation](https://tensorflow.google.cn/beta/tutorials/eager/automatic_differentiation)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/automatic_differentiation.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/automatic_differentiation.md)
#### Custom training: basics (构建tensorflow2.0模型自定义训练的基础步骤)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training.htnl)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/custom_training](https://tensorflow.google.cn/beta/tutorials/eager/custom_training)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training.md)
#### Custom training: walkthrough (使用Keras演示TensorFlow2.0自定义训练实战)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training_walkthrough.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training_walkthrough.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/custom_training_walkthrough](https://tensorflow.google.cn/beta/tutorials/eager/custom_training_walkthrough)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training_walkthrough.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training_walkthrough.md)
#### TF function and AutoGraph (TF梯度下降法的核心自动微分和梯度带)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-automatic_differentiation.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-automatic_differentiation.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/automatic_differentiation](https://tensorflow.google.cn/beta/tutorials/eager/automatic_differentiation)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/automatic_differentiation.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/automatic_differentiation.md)
### Text and sequences
#### Generate text with an RNN(使用RNN生成文本实战:莎士比亚风格诗句)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-text_generation.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-text_generation.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/text/text_generation](https://tensorflow.google.cn/beta/tutorials/text/text_generation)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/text_generation.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/text_generation.md)
#### Neural Machine Translation with Attention(采用注意力机制的神经机器翻译)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-nmt_with_attention.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-nmt_with_attention.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/text/nmt_with_attention](https://tensorflow.google.cn/beta/tutorials/text/nmt_with_attention)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/nmt_with_attention.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/nmt_with_attention.md
#### Image captioning (使用注意力机制给图片取标题)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-image_captioning.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-text-image_captioning.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/text/image_captioning](https://tensorflow.google.cn/beta/tutorials/text/image_captioning)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/image_captioning.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/text/image_captioning.md)
#### Transformer model for language understanding
### Image Generation
### Image Optimization
#### Style Transfer
### GANs
#### DCGAN
#### Pix2Pix
### Auto Encoders
#### VAE
### Loading data
#### Load CSV data
#### Build an image input pipeline
#### Load text with tf.data
#### Use TFRecords and tf.Example
#### Unicode strings
### Distributed training
#### Distributed training
#### Distributed training with custom training loops
#### Multi worker training
## Guide
### Eager essentials
### Variables
### AutoGraph
### Keras
#### Keras overview (Keras概述:构建模型,输入数据,训练,评估,回调,保存,分布)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-keras-overview.html](https://www.mashangxue123.com/tensorflow/tf2-guide-keras-overview.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/keras/overview](https://tensorflow.google.cn/beta/guide/keras/overview)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/overview.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/overview.md)
#### Keras functional API (不用Sequential模型,TensorFlow中的Keras函数式API )
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-keras-functional.html](https://www.mashangxue123.com/tensorflow/tf2-guide-keras-functional.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/keras/functional](https://tensorflow.google.cn/beta/guide/keras/functional)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/functional.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/functional.md)
#### Train and evaluate (使用TensorFlow Keras进行训练和评估)
最新版本:https://www.mashangxue123.com/tensorflow/tf2-guide-keras-training_and_evaluation.html
英文版本:https://tensorflow.google.cn/beta/guide/keras/training_and_evaluation
翻译建议PR:https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/training_and_evaluation.md
#### Write layers and models from scratch
#### Save and serialize models
#### Write custom callbacks
### Accelerators
#### Distribution strategy
#### Using GPU
### Data Loading
#### Performance
### Serialization
#### Checkpoints
#### Saved models
### Misc
#### Version Compatibility
================================================
FILE: r2/guide/eager.md
================================================
---
title: Eager Execution 概述
tags: tensorflow2.0教程
categories: tensorflow2官方教程
top: 1999
abbrlink: tensorflow/tf2-guide-eager
---
# Eager Execution 概述
TensorFlow 的 Eager Execution 是一种命令式编程环境,可立即评估操作,无需构建图:操作会返回具体的值,而不是构建以后再运行的计算图。这样能让您轻松地开始使用 TensorFlow 和调试模型,并且还减少了样板代码。要遵循本指南,请在交互式 python 解释器中运行下面的代码示例。
Eager Execution 是一个灵活的机器学习平台,用于研究和实验,可提供:
* *直观的界面* - 自然地组织代码结构并使用 Python 数据结构。快速迭代小模型和小型数据集。
* *更轻松的调试功能* - 直接调用操作以检查正在运行的模型并测试更改。使用标准 Python 调试工具进行即时错误报告。
* *自然控制流程* - 使用 Python 控制流程而不是图控制流程,简化了动态模型的规范。
Eager Execution 支持大多数 TensorFlow 操作和 GPU 加速。
注意:如果启用 Eager Execution,某些模型的开销可能会增加。我们正在改进性能;如果发现问题,请报告错误,并分享您的基准测试结果。
## 设置和基本用法
升级到最新版本的 TensorFlow:
```python
from __future__ import absolute_import, division, print_function, unicode_literals
# pip install tensorflow==2.0.0-alpha0
import tensorflow as tf
```
在Tensorflow 2.0中,默认情况下启用了Eager Execution。
```python
tf.executing_eagerly()
```
```
True
```
现在您可以运行TensorFlow操作,结果将立即返回:
```python
x = [[2.]]
m = tf.matmul(x, x)
print("hello, {}".format(m))
```
```
hello, [[4.]]
```
启用 Eager Execution 会改变 TensorFlow 操作的行为方式(现在它们会立即评估并将值返回给 Python)。`tf.Tensor` 对象会引用具体值,而不是指向计算图中的节点的符号句柄。由于不需要构建稍后在会话中运行的计算图,因此使用 `print()` 或调试程序很容易检查结果。评估、输出和检查张量值不会中断计算梯度的流程。
Eager Execution 适合与 NumPy 一起使用。NumPy 操作接受`tf.Tensor` 参数。TensorFlow [数学运算](https://tensorflow.google.cn/api_guides/python/math_ops) 将 Python 对象和 NumPy 数组转换为 `tf.Tensor` 对象。`tf.Tensor.numpy` 方法返回对象的值作为 NumPy `ndarray`。
```python
a = tf.constant([[1, 2],
[3, 4]])
print(a)
```
```
tf.Tensor(
[[1 2]
[3 4]], shape=(2, 2), dtype=int32)
```
```python
# Broadcasting support
b = tf.add(a, 1)
print(b)
```
```
tf.Tensor(
[[2 3]
[4 5]], shape=(2, 2), dtype=int32)
```
```python
# Operator overloading is supported
print(a * b)
```
```
tf.Tensor(
[[ 2 6]
[12 20]], shape=(2, 2), dtype=int32)
```
```python
# 使用NumPy值
import numpy as np
c = np.multiply(a, b)
print(c)
```
```
[[ 2 6]
[12 20]]
```
```python
# 从张量中获取numpy值:
print(a.numpy())
# => [[1 2]
# [3 4]]
```
## 动态控制流
Eager Execution 的一个主要好处是,在执行模型时,主机语言的所有功能都可用。因此,编写 [fizzbuzz](https://baike.baidu.com/item/FizzBuzz%E9%97%AE%E9%A2%98/16083686?fr=aladdin)很容易(举例而言):
*FizzBuzz问题:举个例子,编写一个程序从1到100.当遇到数字为3的倍数的时候,点击“Fizz”替代数字,5的倍数用“Buzz”代替,既是3的倍数又是5的倍数点击“FizzBuzz”。*
```python
def fizzbuzz(max_num):
counter = tf.constant(0)
max_num = tf.convert_to_tensor(max_num)
for num in range(1, max_num.numpy()+1):
num = tf.constant(num)
if int(num % 3) == 0 and int(num % 5) == 0:
print('FizzBuzz')
elif int(num % 3) == 0:
print('Fizz')
elif int(num % 5) == 0:
print('Buzz')
else:
print(num.numpy())
counter += 1
```
```python
fizzbuzz(15)
```
```
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz
```
这段代码具有依赖于张量值的条件并在运行时输出这些值。
## 构建模型
许多机器学习模型通过组合层来表示。将 TensorFlow 与 Eager Execution 结合使用时,您可以编写自己的层或使用在 `tf.keras.layers` 程序包中提供的层。
虽然您可以使用任何 Python 对象表示层,但 TensorFlow 提供了便利的基类 `tf.keras.layers.Layer`。您可以通过继承它实现自己的层,如果必须强制执行该层,在构造函数中设置 `self.dynamic=True`:
```python
class MySimpleLayer(tf.keras.layers.Layer):
def __init__(self, output_units):
super(MySimpleLayer, self).__init__()
self.output_units = output_units
self.dynamic = True
def build(self, input_shape):
# The build method gets called the first time your layer is used.
# 构建方法在第一次使用图层时被调用。
# 在build()上创建变量允许您使其形状取决于输入形状,因此无需用户指定完整形状。
# 如果您已经知道它们的完整形状,则可以在` __init__()`期间创建变量。
self.kernel = self.add_variable(
"kernel", [input_shape[-1], self.output_units])
def call(self, input):
# 覆盖 `call()` 而不是`__call__`,这样我们就可以执行一些记帐。
return tf.matmul(input, self.kernel)
```
请使用`tf.keras.layers.Dense`层(而不是上面的`MySimpleLayer`),因为它具有其功能的超集(它也可以添加偏差)。
将层组合成模型时,可以使用 `tf.keras.Sequential` 表示由层线性堆叠的模型。它非常适合用于基本模型:
```python
model = tf.keras.Sequential([
tf.keras.layers.Dense(10, input_shape=(784,)), # must declare input shape
tf.keras.layers.Dense(10)
])
```
或者,通过继承 `tf.keras.Model` 将模型整理为类。这是一个本身也是层的层容器,允许 `tf.keras.Model`对象包含其他 `tf.keras.Model` 对象。
```python
class MNISTModel(tf.keras.Model):
def __init__(self):
super(MNISTModel, self).__init__()
self.dense1 = tf.keras.layers.Dense(units=10)
self.dense2 = tf.keras.layers.Dense(units=10)
def call(self, input):
"""Run the model."""
result = self.dense1(input)
result = self.dense2(result)
result = self.dense2(result) # reuse variables from dense2 layer
return result
model = MNISTModel()
```
因为第一次将输入传递给层时已经设置参数,所以不需要为`tf.keras.Model` 类设置输入形状。
`tf.keras.layers` 类会创建并包含自己的模型变量,这些变量与其层对象的生命周期相关联。要共享层变量,请共享其对象。
## Eager 训练
### 计算梯度
[自动微分](https://en.wikipedia.org/wiki/Automatic_differentiation)对于实现机器学习算法(例如用于训练神经网络的[反向传播](https://en.wikipedia.org/wiki/Backpropagation))来说很有用。在 Eager Execution 期间,请使用 `tf.GradientTape` 跟踪操作以便稍后计算梯度。
`tf.GradientTape` 是一种选择性功能,可在不跟踪时提供最佳性能。由于在每次调用期间都可能发生不同的操作,因此所有前向传播操作都会记录到“磁带”中。要计算梯度,请反向播放磁带,然后放弃。特定的 `tf.GradientTape` 只能计算一个梯度;随后的调用会抛出运行时错误。
```python
w = tf.Variable([[1.0]])
with tf.GradientTape() as tape:
loss = w * w
grad = tape.gradient(loss, w)
print(grad) # => tf.Tensor([[ 2.]], shape=(1, 1), dtype=float32)
```
### 训练模型
以下示例将创建一个多层模型,该模型会对标准 MNIST 手写数字进行分类。它演示了在 Eager Execution 环境中构建可训练图的优化器和层 API。
```python
# 获取并格式化mnist数据
(mnist_images, mnist_labels), _ = tf.keras.datasets.mnist.load_data()
dataset = tf.data.Dataset.from_tensor_slices(
(tf.cast(mnist_images[...,tf.newaxis]/255, tf.float32),
tf.cast(mnist_labels,tf.int64)))
dataset = dataset.shuffle(1000).batch(32)
```
```python
# 建立模型
mnist_model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16,[3,3], activation='relu',
input_shape=(None, None, 1)),
tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(10)
])
```
即使没有训练,也可以在 Eager Execution 中调用模型并检查输出:
```python
for images,labels in dataset.take(1):
print("Logits: ", mnist_model(images[0:1]).numpy())
```
```
Logits: [[-1.9521490e-02 2.2975644e-02 2.8935237e-02 2.0388789e-02 -1.8511273e-02 -6.4317137e-05 6.0662534e-03 -1.7174225e-02 5.4899108e-02 -2.8871424e-02]]
```
虽然 keras 模型具有内置训练循环(使用 `fit` 方法),但有时您需要更多自定义设置。下面是一个用 eager 实现的训练循环示例:
```python
optimizer = tf.keras.optimizers.Adam()
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
loss_history = []
```
```python
for (batch, (images, labels)) in enumerate(dataset.take(400)):
if batch % 10 == 0:
print('.', end='')
with tf.GradientTape() as tape:
logits = mnist_model(images, training=True)
loss_value = loss_object(labels, logits)
loss_history.append(loss_value.numpy().mean())
grads = tape.gradient(loss_value, mnist_model.trainable_variables)
optimizer.apply_gradients(zip(grads, mnist_model.trainable_variables))
```
```python
import matplotlib.pyplot as plt
plt.plot(loss_history)
plt.xlabel('Batch #')
plt.ylabel('Loss [entropy]')
```
```
Text(0, 0.5, 'Loss [entropy]')
```
该示例使用了 [TensorFlow MNIST 示例](https://github.com/tensorflow/models/tree/master/official/mnist) 中的 [dataset.py](https://github.com/tensorflow/models/blob/master/official/mnist/dataset.py) 模块,请将该文件下载到本地目录。运行以下命令以将 MNIST 数据文件下载到工作目录并准备要进行训练的 tf.data.Dataset:
### 变量和优化器
`tf.Variable` 对象会存储在训练期间访问的可变 `tf.Tensor` 值,以更加轻松地实现自动微分。模型的参数可以作为变量封装在类中。
通过将 `tf.Variable` 与 `tf.GradientTape` 结合使用可以更好地封装模型参数。例如,上面的自动微分示例可以重写为:
```python
class Model(tf.keras.Model):
def __init__(self):
super(Model, self).__init__()
self.W = tf.Variable(5., name='weight')
self.B = tf.Variable(10., name='bias')
def call(self, inputs):
return inputs * self.W + self.B
# 点数约为3 * x + 2的玩具数据集
NUM_EXAMPLES = 2000
training_inputs = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
training_outputs = training_inputs * 3 + 2 + noise
# 要优化的损失函数
def loss(model, inputs, targets):
error = model(inputs) - targets
return tf.reduce_mean(tf.square(error))
def grad(model, inputs, targets):
with tf.GradientTape() as tape:
loss_value = loss(model, inputs, targets)
return tape.gradient(loss_value, [model.W, model.B])
# Define:
# 1. A model.
# 2. Derivatives of a loss function with respect to model parameters.
# 3. A strategy for updating the variables based on the derivatives.
model = Model()
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)
print("Initial loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
# Training loop
for i in range(300):
grads = grad(model, training_inputs, training_outputs)
optimizer.apply_gradients(zip(grads, [model.W, model.B]))
if i % 20 == 0:
print("Loss at step {:03d}: {:.3f}".format(i, loss(model, training_inputs, training_outputs)))
print("Final loss: {:.3f}".format(loss(model, training_inputs, training_outputs)))
print("W = {}, B = {}".format(model.W.numpy(), model.B.numpy()))
```
## 在Eager Execution期间将对象用于状态
使用 TF 1.x的 Graph Execution 时,程序状态(如变量)存储在全局集合中,它们的生命周期由 `tf.Session` 对象管理。相反,在Eager Execution期间,状态对象的生命周期由其对应的 Python 对象的生命周期决定。
### 变量是对象
在 Eager Execution 期间,变量会一直存在,直到相应对象的最后一个引用被移除,然后变量被删除。
```python
if tf.test.is_gpu_available():
with tf.device("gpu:0"):
v = tf.Variable(tf.random.normal([1000, 1000]))
v = None # v no longer takes up GPU memory
```
### 基于对象的保存
本节是[训练检查点指南](https://tensorflow.google.cn/beta/guide/checkpoints)的简短版本。
`tf.train.Checkpoint` 可以将 `tf.Variable` 保存到检查点并从中恢复:
```python
x = tf.Variable(10.)
checkpoint = tf.train.Checkpoint(x=x)
```
```
x.assign(2.) # 为变量分配新值并保存。
checkpoint_path = './ckpt/'
checkpoint.save('./ckpt/')
```
```python
x.assign(11.) # 保存后更改变量。
# 从检查点恢复值
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))
print(x) # => 2.0
```
要保存和加载模型,`tf.train.Checkpoint` 会存储对象的内部状态,而不需要隐藏变量。要记录 `model`、`optimizer` 和全局步的状态,请将它们传递到 `tf.train.Checkpoint`:
```python
import os
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(16,[3,3], activation='relu'),
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(10)
])
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
checkpoint_dir = 'path/to/model_dir'
if not os.path.exists(checkpoint_dir):
os.makedirs(checkpoint_dir)
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
root = tf.train.Checkpoint(optimizer=optimizer,
model=model)
root.save(checkpoint_prefix)
root.restore(tf.train.latest_checkpoint(checkpoint_dir))
```
注意:在许多训练循环中,在调用`tf.train.Checkpoint.restore`之后创建变量。这些变量将在创建后立即恢复,并且可以使用断言来确保检查点已完全加载。有关详细信息,请参阅[训练检查点指南](https://tensorflow.google.cn/beta/guide/checkpoints)。
### 面向对象的指标
`tf.keras.metrics`存储为对象。通过将新数据传递给可调用对象来更新指标,并使用 `tf.keras.metrics.result`方法检索结果,例如:
```python
m = tf.keras.metrics.Mean("loss")
m(0)
m(5)
m.result() # => 2.5
m([8, 9])
m.result() # => 5.5
```
## 自动微分高级内容
### 动态模型
`tf.GradientTape` 也可用于动态模型。这个回溯线搜索算法示例看起来像普通的 NumPy 代码,除了存在梯度并且可微分,尽管控制流比较复杂:
```python
def line_search_step(fn, init_x, rate=1.0):
with tf.GradientTape() as tape:
# Variables are automatically recorded, but manually watch a tensor
tape.watch(init_x)
value = fn(init_x)
grad = tape.gradient(value, init_x)
grad_norm = tf.reduce_sum(grad * grad)
init_value = value
while value > init_value - rate * grad_norm:
x = init_x - rate * grad
value = fn(x)
rate /= 2.0
return x, value
```
### 自定义梯度
自定义梯度是一种覆盖梯度的简单方法。在正向函数中,定义相对于输入、输出或中间结果的梯度。例如,下面是在反向传播中截断梯度范数的一种简单方式:
```python
@tf.custom_gradient
def clip_gradient_by_norm(x, norm):
y = tf.identity(x)
def grad_fn(dresult):
return [tf.clip_by_norm(dresult, norm), None]
return y, grad_fn
```
自定义梯度通常用于为一系列操作提供数值稳定的梯度:
```python
def log1pexp(x):
return tf.math.log(1 + tf.exp(x))
def grad_log1pexp(x):
with tf.GradientTape() as tape:
tape.watch(x)
value = log1pexp(x)
return tape.gradient(value, x)
```
```python
# 梯度计算在x = 0时工作正常。
grad_log1pexp(tf.constant(0.)).numpy() # => 0.5
```
`0.5`
```python
# 但是,由于数值不稳定,x = 100失败。
grad_log1pexp(tf.constant(100.)).numpy() # => nan
```
`nan`
在此处,`log1pexp` 函数可以通过自定义梯度进行分析简化。下面的实现重用了在前向传播期间计算的`tf.exp(x)`的值,通过消除冗余计算,变得更加高效:
```python
@tf.custom_gradient
def log1pexp(x):
e = tf.exp(x)
def grad(dy):
return dy * (1 - 1 / (1 + e))
return tf.math.log(1 + e), grad
def grad_log1pexp(x):
with tf.GradientTape() as tape:
tape.watch(x)
value = log1pexp(x)
return tape.gradient(value, x)
```
```python
# 和以前一样,梯度计算在x = 0时工作正常。
grad_log1pexp(tf.constant(0.)).numpy() # => 0.5
```
```python
# 并且梯度计算也适用于x = 100。
grad_log1pexp(tf.constant(100.)).numpy() # => 1.0
```
## 性能
在Eager Execution期间,计算会自动分流到 GPU。如果要控制计算运行的位置,可以将其放在`tf.device('/gpu:0')` 块(或 CPU 等效块)中:
```python
import time
def measure(x, steps):
# TensorFlow在第一次使用时初始化GPU,从计时中排除。
tf.matmul(x, x)
start = time.time()
for i in range(steps):
x = tf.matmul(x, x)
# tf.matmul can return before completing the matrix multiplication
# (e.g., can return after enqueing the operation on a CUDA stream).
# The x.numpy() call below will ensure that all enqueued operations
# have completed (and will also copy the result to host memory,
# so we're including a little more than just the matmul operation
# time).
_ = x.numpy()
end = time.time()
return end - start
shape = (1000, 1000)
steps = 200
print("Time to multiply a {} matrix by itself {} times:".format(shape, steps))
# Run on CPU:
with tf.device("/cpu:0"):
print("CPU: {} secs".format(measure(tf.random.normal(shape), steps)))
# Run on GPU, if available:
if tf.test.is_gpu_available():
with tf.device("/gpu:0"):
print("GPU: {} secs".format(measure(tf.random.normal(shape), steps)))
else:
print("GPU: not found")
```
```
Time to multiply a (1000, 1000) matrix by itself 200 times:
CPU: 0.7741374969482422 secs
GPU: not found
```
`tf.Tensor`对象可以复制到不同的设备来执行其操作:
```python
if tf.test.is_gpu_available():
x = tf.random.normal([10, 10])
x_gpu0 = x.gpu()
x_cpu = x.cpu()
_ = tf.matmul(x_cpu, x_cpu) # Runs on CPU
_ = tf.matmul(x_gpu0, x_gpu0) # Runs on GPU:0
```
### 基准
对于计算量繁重的模型(如在 GPU 上训练的 [ResNet50](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/eager/python/examples/resnet50)),Eager Execution 性能与 `tf.function` Execution 相当。但是对于计算量较小的模型来说,这种性能差距会越来越大,并且有很多工作要做,以便为具有大量小操作的模型优化热代码路径。
## 使用`tf.function`
虽然Eager Execution使开发和调试更具交互性,但TensorFlow 1.x样式图执行在分布式训练,性能优化和生产部署方面具有优势。为了弥补这一差距,TensorFlow 2.0通过`tf.function` API引入此功能。有关更多信息,请参阅[Autograph指南](https://tensorflow.google.cn/beta/guide/autograph)。
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-eager.html](https://www.mashangxue123.com/tensorflow/tf2-guide-eager.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/eager](https://tensorflow.google.cn/beta/guide/eager)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/eager.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/eager.md)
================================================
FILE: r2/guide/effective_tf2.md
================================================
---
title: 高效的TensorFlow 2.0
tags:
- tensorflow2.0
categories:
- tensorflow2官方教程
top: 1902
abbrlink: tensorflow/tf2-guide-effective_tf2
---
# 高效的TensorFlow 2.0 (tensorflow2.0官方教程翻译)
TensorFlow 2.0中有多处更改,以使TensorFlow用户使用更高效。TensorFlow 2.0删除[冗余 APIs](https://github.com/tensorflow/community/blob/master/rfcs/20180827-api-names.md),使API更加一致([统一 RNNs](https://github.com/tensorflow/community/blob/master/rfcs/20180920-unify-rnn-interface.md),[统一优化器](https://github.com/tensorflow/community/blob/master/rfcs/20181016-optimizer-unification.md)),并通过[Eager execution](https://www.tensorflow.org/guide/eager)模式更好地与Python运行时集成
许多[RFCs](https://github.com/tensorflow/community/pulls?utf8=%E2%9C%93&q=is%3Apr)已经解释了TensorFlow 2.0所带来的变化。本指南介绍了TensorFlow 2.0应该是什么样的开发,假设您对TensorFlow 1.x有一定的了解。
## 1. 主要变化的简要总结
### 1.1. API清理
许多API在tensorflow 2.0中[消失或移动](https://github.com/tensorflow/community/blob/master/rfcs/20180827-api-names.md)。一些主要的变化包括删除`tf.app`、`tf.flags`和`tf.logging` ,转而支持现在开源的[absl-py](https://github.com/abseil/abseil-py),重新安置`tf.contrib`中的项目,并清理主要的 `tf.*`命名空间,将不常用的函数移动到像 `tf.math`这样的子包中。一些API已被2.0版本等效替换,如`tf.summary`, `tf.keras.metrics`和`tf.keras.optimizers`。
自动应用这些重命名的最简单方法是使用[v2升级脚本](https://tensorflow.google.cn/beta/guide/upgrade)。
### 1.2. Eager execution
TensorFlow 1.X要求用户通过进行`tf.*` API调用,手动将抽象语法树(图形)拼接在一起。然后要求用户通过将一组输出张量和输入张量传递给`session.run()`来手动编译抽象语法树。
TensorFlow 2.0 默认Eager execution模式,马上就执行代码(就像Python通常那样),在2.0中,图形和会话应该像实现细节一样。
Eager execution的一个值得注意的地方是不在需要`tf.control_dependencies()` ,因为所有代码按顺序执行(在`tf.function`中,带有副作用的代码按写入的顺序执行)。
### 1.3. 没有更多的全局变量
TensorFlow 1.X严重依赖于隐式全局命名空间。当你调用`tf.Variable()`时,它会被放入默认图形中,保留在那里,即使你忘记了指向它的Python变量。
然后,您可以恢复该`tf.Variable`,但前提是您知道它已创建的名称,如果您无法控制变量的创建,这很难做到。结果,各种机制激增,试图帮助用户再次找到他们的变量,并寻找框架来查找用户创建的变量:变量范围、全局集合、辅助方法如`tf.get_global_step()`, `tf.global_variables_initializer()`、优化器隐式计算所有可训练变量的梯度等等。
TensorFlow 2.0取消了所有这些机制([Variables 2.0 RFC](https://github.com/tensorflow/community/pull/11)),支持默认机制:跟踪变量!如果你失去了对tf.Variable的追踪,就会垃圾收集回收。
跟踪变量的要求为用户创建了一些额外的工作,但是使用Keras对象(见下文),负担被最小化。
### 1.4. Functions, not sessions
`session.run()`调用几乎就像一个函数调用:指定输入和要调用的函数,然后返回一组输出。
在TensorFlow 2.0中,您可以使用`tf.function()` 来装饰Python函数以将其标记为JIT编译,以便TensorFlow将其作为单个图形运行([Functions 2.0 RFC](https://github.com/tensorflow/community/pull/20))。这种机制允许TensorFlow 2.0获得图形模式的所有好处:
- 性能:可以优化功能(节点修剪,内核融合等)
- 可移植性:该功能可以导出/重新导入([SavedModel 2.0 RFC](https://github.com/tensorflow/community/pull/34)),允许用户重用和共享模块化TensorFlow功能。
```python
# TensorFlow 1.X
outputs = session.run(f(placeholder), feed_dict={placeholder: input})
# TensorFlow 2.0
outputs = f(input)
```
凭借能够自由穿插Python和TensorFlow代码,我们希望用户能够充分利用Python的表现力。但是可移植的TensorFlow在没有Python解释器的情况下执行-移动端、C++和JS,帮助用户避免在添加 `@tf.function`时重写代码,[AutoGraph](https://tensorflow.google.cn/beta/guide/autograph)将把Python构造的一个子集转换成它们等效的TensorFlow:
* `for`/`while` -> `tf.while_loop` (支持`break` 和 `continue`)
* `if` -> `tf.cond`
* `for _ in dataset` -> `dataset.reduce`
AutoGraph支持控制流的任意嵌套,这使得高效和简洁地实现许多复杂的ML程序成为可能,比如序列模型、强化学习、自定义训练循环等等。
## 2. 使用TensorFlow 2.0的建议
### 2.1. 将代码重构为更小的函数
TensorFlow 1.X中常见的使用模式是“kitchen sink”策略,在该策略中,所有可能的计算的并集被预先安排好,然后通过`session.run()`对所选的张量进行评估。
TensorFlow 2.0中,用户应该根据需要将代码重构为更小的函数。一般来说,没有必须要使用`tf.function`来修饰这些小函数,只用`tf.function`来修饰高级计算-例如,一个训练步骤,或者模型的前向传递。
### 2.2. 使用Keras层和模型来管理变量
Keras模型和层提供了方便的`variables`和`trainable_variables`属性,它们递归地收集所有的因变量。这使得本地管理变量到使用它们的地方变得非常容易。
对比如下:
```python
def dense(x, W, b):
return tf.nn.sigmoid(tf.matmul(x, W) + b)
@tf.function
def multilayer_perceptron(x, w0, b0, w1, b1, w2, b2 ...):
x = dense(x, w0, b0)
x = dense(x, w1, b1)
x = dense(x, w2, b2)
...
# 您仍然必须管理w_i和b_i,它们是在代码的其他地方定义的。
```
Keras版本如下:
```python
# 每个图层都可以调用,其签名等价于linear(x)
layers = [tf.keras.layers.Dense(hidden_size, activation=tf.nn.sigmoid) for _ in range(n)]
perceptron = tf.keras.Sequential(layers)
# layers[3].trainable_variables => returns [w3, b3]
# perceptron.trainable_variables => returns [w0, b0, ...]
```
Keras 层/模型继承自 `tf.train.Checkpointable` 并与`@tf.function`集成,这使得从Keras对象导出保存模型成为可能。
您不必使用Keras的`.fit()` API来利用这些集成。
下面是一个转移学习示例,演示了Keras如何简化收集相关变量子集的工作。假设你正在训练一个拥有共享trunk的multi-headed模型:
```python
trunk = tf.keras.Sequential([...])
head1 = tf.keras.Sequential([...])
head2 = tf.keras.Sequential([...])
path1 = tf.keras.Sequential([trunk, head1])
path2 = tf.keras.Sequential([trunk, head2])
# 训练主要数据集
for x, y in main_dataset:
with tf.GradientTape() as tape:
prediction = path1(x)
loss = loss_fn_head1(prediction, y)
# 同时优化trunk和head1的权重
gradients = tape.gradient(loss, path1.trainable_variables)
optimizer.apply_gradients(zip(gradients, path1.trainable_variables))
# 微调第二个头部,重用trunk
for x, y in small_dataset:
with tf.GradientTape() as tape:
prediction = path2(x)
loss = loss_fn_head2(prediction, y)
# 只优化head2的权重,不是trunk的权重
gradients = tape.gradient(loss, head2.trainable_variables)
optimizer.apply_gradients(zip(gradients, head2.trainable_variables))
# 你可以发布trunk计算,以便他人重用。
tf.saved_model.save(trunk, output_path)
```
### 2.3. 结合tf.data.Datesets和@tf.function
当迭代适合内存训练的数据时,可以随意使用常规的Python迭代。除此之外,`tf.data.Datesets`是从磁盘中传输训练数据的最佳方式。
数据集[可迭代(但不是迭代器](https://docs.python.org/3/glossary.html#term-iterable)),就像其他Python迭代器在Eager模式下工作一样。
您可以通过将代码包装在`tf.function()`中来充分利用数据集异步预取/流功能,该代码将Python迭代替换为使用AutoGraph的等效图形操作。
```python
@tf.function
def train(model, dataset, optimizer):
for x, y in dataset:
with tf.GradientTape() as tape:
prediction = model(x)
loss = loss_fn(prediction, y)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
```
如果使用Keras`.fit()`API,就不必担心数据集迭代:
```python
model.compile(optimizer=optimizer, loss=loss_fn)
model.fit(dataset)
```
### 2.4. 利用AutoGraph和Python控制流程
AutoGraph提供了一种将依赖于数据的控制流转换为图形模式等价的方法,如`tf.cond`和`tf.while_loop`。
数据依赖控制流出现的一个常见位置是序列模型。`tf.keras.layers.RNN`封装一个RNN单元格,允许你您静态或动态展开递归。
为了演示,您可以重新实现动态展开如下:
```python
class DynamicRNN(tf.keras.Model):
def __init__(self, rnn_cell):
super(DynamicRNN, self).__init__(self)
self.cell = rnn_cell
def call(self, input_data):
# [batch, time, features] -> [time, batch, features]
input_data = tf.transpose(input_data, [1, 0, 2])
outputs = tf.TensorArray(tf.float32, input_data.shape[0])
state = self.cell.zero_state(input_data.shape[1], dtype=tf.float32)
for i in tf.range(input_data.shape[0]):
output, state = self.cell(input_data[i], state)
outputs = outputs.write(i, output)
return tf.transpose(outputs.stack(), [1, 0, 2]), state
```
有关AutoGraph功能的更详细概述,请参阅[指南](https://tensorflow.google.cn/beta/guide/autograph).。
### 2.5. 使用tf.metrics聚合数据和tf.summary来记录它
要记录摘要,请使用`tf.summary.(scalar|histogram|...)` 并使用上下文管理器将其重定向到writer。(如果省略上下文管理器,则不会发生任何事情。)与TF 1.x不同,摘要直接发送给writer;没有单独的`merger`操作,也没有单独的`add_summary()`调用,这意味着必须在调用点提供步骤值。
```python
summary_writer = tf.summary.create_file_writer('/tmp/summaries')
with summary_writer.as_default():
tf.summary.scalar('loss', 0.1, step=42)
```
要在将数据记录为摘要之前聚合数据,请使用`tf.metrics`,Metrics是有状态的;
当你调用`.result()`时,它们会累计值并返回累计结果。使用`.reset_states()`清除累计值。
```python
def train(model, optimizer, dataset, log_freq=10):
avg_loss = tf.keras.metrics.Mean(name='loss', dtype=tf.float32)
for images, labels in dataset:
loss = train_step(model, optimizer, images, labels)
avg_loss.update_state(loss)
if tf.equal(optimizer.iterations % log_freq, 0):
tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations)
avg_loss.reset_states()
def test(model, test_x, test_y, step_num):
loss = loss_fn(model(test_x), test_y)
tf.summary.scalar('loss', loss, step=step_num)
train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train')
test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test')
with train_summary_writer.as_default():
train(model, optimizer, dataset)
with test_summary_writer.as_default():
test(model, test_x, test_y, optimizer.iterations)
```
通过将TensorBoard指向摘要日志目录来显示生成的摘要:
```shell
tensorboard --logdir /tmp/summaries
```
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-effective_tf2.html](https://www.mashangxue123.com/tensorflow/tf2-guide-effective_tf2.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/effective_tf2](https://tensorflow.google.cn/beta/guide/effective_tf2)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/effective_tf2.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/effective_tf2.md)
================================================
FILE: r2/guide/keras/functional.md
================================================
---
title: 不用Sequential模型,TensorFlow中的Keras函数式API
tags: tensorflow2.0教程
categories: tensorflow2官方教程
top: 1999
abbrlink: tensorflow/tf2-guide-keras-functional
---
# 不用Sequential模型,TensorFlow中的Keras函数式API (tensorflow2.0官方教程翻译)
## 1. 设置
安装
```
pip install pydot
apt-get install graphviz
```
导入库
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
tf.keras.backend.clear_session() # For easy reset of notebook state.
```
## 2. 介绍
您已经熟悉使用 `keras.Sequential()` 来创建模型。函数式 API是一种创建比 `Sequential` 更灵活的模型的方法:它可以处理具有非线性拓扑的模型,具有共享层的模型以及具有多个输入或输出的模型。
它基于这样一种思想,即深度学习模型通常是由层组成的有向无环图(DAG)。函数API是一组用于构建层图的工具。
考虑以下模型:
```python
(input: 784-dimensional vectors)
↧
[Dense (64 units, relu activation)]
↧
[Dense (64 units, relu activation)]
↧
[Dense (10 units, softmax activation)]
↧
(output: probability distribution over 10 classes)
```
这是一个3层的简单图表。
要使用函数API构建这个模型,首先要创建一个输入节点:
```python
from tensorflow import keras
inputs = keras.Input(shape=(784,))
```
这里我们只指定数据的形状:784维向量。无论总是省略批量大小,我们只指定每个样本的形状。对于用于形状 `(32, 32, 3)` 的图像的输入,我们将使用:
```python
img_inputs = keras.Input(shape=(32, 32, 3))
```
返回的内容,`inputs`,包含有关您希望提供给模型的输入数据的形状和类型的信息:
```python
inputs.shape
inputs.dtype
```
```
TensorShape([None, 784])
tf.float32
```
通过调用这个输入对象上的一个层,可以在层图中创建一个新节点:
```python
from tensorflow.keras import layers
dense = layers.Dense(64, activation='relu')
x = dense(inputs)
```
“层调用”操作就像从“输入”向我们创建的这个层绘制一个箭头。我们把输入“传递”到 `dense` 层,得到x。
让我们在图层中添加几个层:
```python
x = layers.Dense(64, activation='relu')(x)
outputs = layers.Dense(10, activation='softmax')(x)
```
此时,我们可以通过在图层中指定其输入和输出来创建模型:
```python
model = keras.Model(inputs=inputs, outputs=outputs)
```
回顾一下,这是我们的完整模型定义过程:
```python
inputs = keras.Input(shape=(784,), name='img')
x = layers.Dense(64, activation='relu')(inputs)
x = layers.Dense(64, activation='relu')(x)
outputs = layers.Dense(10, activation='softmax')(x)
model = keras.Model(inputs=inputs, outputs=outputs, name='mnist_model')
```
让我们看一下模型摘要的样子:
```python
model.summary()
```
```
Model: "mnist_model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
img (InputLayer) [(None, 784)] 0
_________________________________________________________________
dense_3 (Dense) (None, 64) 50240
_________________________________________________________________
dense_4 (Dense) (None, 64) 4160
_________________________________________________________________
dense_5 (Dense) (None, 10) 650
=================================================================
Total params: 55,050
Trainable params: 55,050
Non-trainable params: 0
_________________________________________________________________
```
我们还可以将模型绘制为图形:
```python
keras.utils.plot_model(model, 'my_first_model.png')
```

并可选择在绘制的图形中显示每个图层的输入和输出形状:
```python
keras.utils.plot_model(model, 'my_first_model_with_shape_info.png', show_shapes=True)
```

这个图和我们编写的代码几乎完全相同。在代码版本中,连接箭头只是由调用操作替换。
"graph of layers" 是深度学习模型的非常直观的心理图像,而函数API是一种创建模型的方法,可以很好地反映这种心理图像。
## 3. 训练、评估和推理
对于使用函数API构建的模型和顺序模型,评估和推理的工作方式完全相同。
这是一个快速演示。
在这里,我们加载MNIST图像数据,将其重新整形为矢量,使模型适合数据(同时监控验证分割的性能),最后我们在测试数据上评估我们的模型:
```python
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255
model.compile(loss='sparse_categorical_crossentropy',
optimizer=keras.optimizers.RMSprop(),
metrics=['accuracy'])
history = model.fit(x_train, y_train,
batch_size=64,
epochs=5,
validation_split=0.2)
test_scores = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', test_scores[0])
print('Test accuracy:', test_scores[1])
```
```
Train on 48000 samples, validate on 12000 samples
......
Epoch 5/5
48000/48000 [==============================] - 3s 55us/sample - loss: 0.0759 - accuracy: 0.9770 - val_loss: 0.1139 - val_accuracy: 0.9670
Test loss: 0.100577776569454
Test accuracy: 0.9696
```
有关模型训练和评估的完整指南,请参阅[训练和评估指南](https://tensorflow.google.cn/beta/guide/keras/training_and_evaluation)。
## 4. 保存和序列化
对于使用函数API构建的模型和顺序模型,保存和序列化的工作方式完全相同。
保存函数模型的标准方法是调用model.save()将整个模型保存到一个文件中。稍后,您可以从该文件重新创建相同的模型,即使您不再能够访问创建模型的代码。
这个文件包括:
- 该模型的架构
- 模型的权重值(在训练期间学到的)
- 模型的训练配置(你传递给`compile`的东西),如果有的话
- 优化器及其状态(如果有的话)(这使您可以从中断的地方重新启动训练)
```python
model.save('path_to_my_model.h5')
del model
# Recreate the exact same model purely from the file:
model = keras.models.load_model('path_to_my_model.h5')
```
有关模型保存的完整指南,请参阅[保存和序列化模型指南](https://tensorflow.google.cn/beta/guide/keras/saving_and_serializing)。
## 5. 使用相同的层图来定义多个模型
在函数API中,通过在层图中指定它们的输入和输出来创建模型。这意味着一个图层图可以用来生成多个模型。
在下面的示例中,我们使用相同的层堆栈来实例化两个模型:将图像输入转换为16维向量的编码器 `encoder` 模型,以及用于训练的端到端自动编码器`autoencoder`模型。
```python
encoder_input = keras.Input(shape=(28, 28, 1), name='img')
x = layers.Conv2D(16, 3, activation='relu')(encoder_input)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.Conv2D(16, 3, activation='relu')(x)
encoder_output = layers.GlobalMaxPooling2D()(x)
encoder = keras.Model(encoder_input, encoder_output, name='encoder')
encoder.summary()
x = layers.Reshape((4, 4, 1))(encoder_output)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
x = layers.Conv2DTranspose(32, 3, activation='relu')(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation='relu')(x)
autoencoder = keras.Model(encoder_input, decoder_output, name='autoencoder')
autoencoder.summary()
```
请注意,我们使解码架构与编码架构严格对称,因此我们得到的输出形状与输入形状`(28,28,1)`相同。`Conv2D` 层的反面是 `Conv2DTranspose` 层`MaxPooling2D` 层的反面是 `UpSampling2D` 层。
## 6. 所有模型都可以调用,就像层一样
您可以将任何模型视为一个图层,方法是在输入或另一个图层的输出上调用它。请注意,通过调用模型,您不仅可以重用模型的体系结构,还可以重用其权重。
让我们看看它是如何运作的。以下是对自动编码器示例的不同看法,该示例创建编码器模型,解码器模型,并在两次调用中链接它们以获取自动编码器模型:
```python
encoder_input = keras.Input(shape=(28, 28, 1), name='original_img')
x = layers.Conv2D(16, 3, activation='relu')(encoder_input)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.Conv2D(16, 3, activation='relu')(x)
encoder_output = layers.GlobalMaxPooling2D()(x)
encoder = keras.Model(encoder_input, encoder_output, name='encoder')
encoder.summary()
decoder_input = keras.Input(shape=(16,), name='encoded_img')
x = layers.Reshape((4, 4, 1))(decoder_input)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
x = layers.Conv2DTranspose(32, 3, activation='relu')(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation='relu')(x)
decoder = keras.Model(decoder_input, decoder_output, name='decoder')
decoder.summary()
autoencoder_input = keras.Input(shape=(28, 28, 1), name='img')
encoded_img = encoder(autoencoder_input)
decoded_img = decoder(encoded_img)
autoencoder = keras.Model(autoencoder_input, decoded_img, name='autoencoder')
autoencoder.summary()
```
如您所见,模型可以嵌套:模型可以包含子模型(因为模型就像一个层)。
模型嵌套的常见用例是集成。作为一个例子,这里是如何将一组模型集成到一个平均其预测的模型中:
```python
def get_model():
inputs = keras.Input(shape=(128,))
outputs = layers.Dense(1, activation='sigmoid')(inputs)
return keras.Model(inputs, outputs)
model1 = get_model()
model2 = get_model()
model3 = get_model()
inputs = keras.Input(shape=(128,))
y1 = model1(inputs)
y2 = model2(inputs)
y3 = model3(inputs)
outputs = layers.average([y1, y2, y3])
ensemble_model = keras.Model(inputs=inputs, outputs=outputs)
```
## 7. 操纵复杂的图形拓扑
### 7.1. 具有多个输入和输出的模型
functional API使操作多个输入和输出变得容易。使用Sequential API无法处理此问题。
这是一个简单的例子。
假设您正在构建一个系统,按照优先级对定制的发行票据进行排序,并将它们路由到正确的部门。
你的模型将有3个输入:
- 票证标题(文字输入)
- 票证的文本正文(文本输入)
- 用户添加的任何标签(分类输入)
它将有两个输出:
- 优先级在0到1之间(标量sigmoid输出)
- 应该处理票据的部门(各部门之间的softmax输出)
让我们用Functional API在几行中构建这个模型。
```python
num_tags = 12 # Number of unique issue tags
num_words = 10000 # Size of vocabulary obtained when preprocessing text data
num_departments = 4 # Number of departments for predictions
title_input = keras.Input(shape=(None,), name='title') # Variable-length sequence of ints
body_input = keras.Input(shape=(None,), name='body') # Variable-length sequence of ints
tags_input = keras.Input(shape=(num_tags,), name='tags') # Binary vectors of size `num_tags`
# Embed each word in the title into a 64-dimensional vector
title_features = layers.Embedding(num_words, 64)(title_input)
# Embed each word in the text into a 64-dimensional vector
body_features = layers.Embedding(num_words, 64)(body_input)
# Reduce sequence of embedded words in the title into a single 128-dimensional vector
title_features = layers.LSTM(128)(title_features)
# Reduce sequence of embedded words in the body into a single 32-dimensional vector
body_features = layers.LSTM(32)(body_features)
# Merge all available features into a single large vector via concatenation
x = layers.concatenate([title_features, body_features, tags_input])
# Stick a logistic regression for priority prediction on top of the features
priority_pred = layers.Dense(1, activation='sigmoid', name='priority')(x)
# Stick a department classifier on top of the features
department_pred = layers.Dense(num_departments, activation='softmax', name='department')(x)
# Instantiate an end-to-end model predicting both priority and department
model = keras.Model(inputs=[title_input, body_input, tags_input],
outputs=[priority_pred, department_pred])
```
让我们绘制模型:
```python
keras.utils.plot_model(model, 'multi_input_and_output_model.png', show_shapes=True)
```

编译此模型时,我们可以为每个输出分配不同的损耗。您甚至可以为每个损失分配不同的权重,以调整它们对总训练损失的贡献。
```python
model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
loss=['binary_crossentropy', 'categorical_crossentropy'],
loss_weights=[1., 0.2])
```
由于我们为输出图层指定了名称,因此我们也可以像这样指定损失:
```python
model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
loss={'priority': 'binary_crossentropy',
'department': 'categorical_crossentropy'},
loss_weights=[1., 0.2])
```
我们可以通过传递Numpy输入和目标数组列表来训练模型:
```python
import numpy as np
# Dummy input data
title_data = np.random.randint(num_words, size=(1280, 10))
body_data = np.random.randint(num_words, size=(1280, 100))
tags_data = np.random.randint(2, size=(1280, num_tags)).astype('float32')
# Dummy target data
priority_targets = np.random.random(size=(1280, 1))
dept_targets = np.random.randint(2, size=(1280, num_departments))
model.fit({'title': title_data, 'body': body_data, 'tags': tags_data},
{'priority': priority_targets, 'department': dept_targets},
epochs=2,
batch_size=32)
```
```
....
Epoch 2/2
1280/1280 [==============================] - 11s 9ms/sample - loss: 1.2137 - priority_loss: 0.6489 - department_loss: 2.8242
```
当使用`Dataset`对象调用fit时,它应该产生一个列表元组,如 `([title_data, body_data, tags_data], [priority_targets, dept_targets])` 或者一个字典的元组 `({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets})`。
有关更详细的说明,请参阅完整的[训练和评估指南](https://tensorflow.google.cn/beta/guide/keras/training_and_evaluation)。
### 7.2. 一个玩具resnet模型
除了具有多个输入和输出的模型之外,Functional API还可以轻松地操作非线性连接拓扑,也就是说,层不按顺序连接的模型。这也无法使用Sequential API处理(如名称所示)。
一个常见的用例是残差连接。
让我们为CIFAR10构建一个玩具ResNet模型来演示这个
```python
inputs = keras.Input(shape=(32, 32, 3), name='img')
x = layers.Conv2D(32, 3, activation='relu')(inputs)
x = layers.Conv2D(64, 3, activation='relu')(x)
block_1_output = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(64, 3, activation='relu', padding='same')(block_1_output)
x = layers.Conv2D(64, 3, activation='relu', padding='same')(x)
block_2_output = layers.add([x, block_1_output])
x = layers.Conv2D(64, 3, activation='relu', padding='same')(block_2_output)
x = layers.Conv2D(64, 3, activation='relu', padding='same')(x)
block_3_output = layers.add([x, block_2_output])
x = layers.Conv2D(64, 3, activation='relu')(block_3_output)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(256, activation='relu')(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10, activation='softmax')(x)
model = keras.Model(inputs, outputs, name='toy_resnet')
model.summary()
```
让我们绘制模型:
```python
keras.utils.plot_model(model, 'mini_resnet.png', show_shapes=True)
```

我们来训练吧:
```python
(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)
model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
loss='categorical_crossentropy',
metrics=['acc'])
model.fit(x_train, y_train,
batch_size=64,
epochs=1,
validation_split=0.2)
```
```
Train on 40000 samples, validate on 10000 samples
40000/40000 [==============================] - 318s 8ms/sample - loss: 1.9034 - acc: 0.2767 - val_loss: 1.6173 - val_acc: 0.3870
```
## 8. 共享图层
函数式API的另一个好用途是使用共享层的模型。共享图层是在同一模型中多次重复使用的图层实例:它们学习与层图中的多个路径对应的特征。
共享层通常用于编码来自类似空间的输入(例如,两个不同的文本,具有相似的词汇表),因为它们可以在这些不同的输入上共享信息,并且可以在更少的时间内训练这样的模型数据。如果在其中一个输入中看到给定的单词,那将有利于处理通过共享层的所有输入。
要在Functional API中共享图层,只需多次调用同一图层实例即可。例如,这是一个跨两个不同文本输入共享的嵌入`Embedding` 层:
```python
# Embedding for 1000 unique words mapped to 128-dimensional vectors
shared_embedding = layers.Embedding(1000, 128)
# Variable-length sequence of integers
text_input_a = keras.Input(shape=(None,), dtype='int32')
# Variable-length sequence of integers
text_input_b = keras.Input(shape=(None,), dtype='int32')
# We reuse the same layer to encode both inputs
encoded_input_a = shared_embedding(text_input_a)
encoded_input_b = shared_embedding(text_input_b)
```
## 9. 提取和重用图层中的节点
因为您在Functional API中操作的层图是静态数据结构,所以可以访问和检查它。这就是我们如何将功能模型绘制为图像的方式。
这也意味着我们可以访问中间层的激活(图中的“节点”)并在其他地方重用它们。例如,这对于特征提取非常有用!
让我们看一个例子。这是一个在ImageNet上预先训练权重的VGG19模型:
```python
from tensorflow.keras.applications import VGG19
vgg19 = VGG19()
```
这些是模型的中间激活,通过查询图形数据结构获得:
```python
features_list = [layer.output for layer in vgg19.layers]
```
我们可以使用这些功能来创建一个新的特征提取模型,它返回中间层激活的值(我们可以在3行中完成所有这些操作)。
```python
feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)
img = np.random.random((1, 224, 224, 3)).astype('float32')
extracted_features = feat_extraction_model(img)
```
除了其他方面,这在[实现神经风格迁移](https://medium.com/tensorflow/neural-style-transfer-creating-art-with-deep-learning-using-tf-keras-and-eager-execution-7d541ac31398)时派上用场。
## 10. 通过编写自定义图层来扩展API
tf.keras拥有广泛的内置层。这里有一些例子:
- 卷积层Convolutional layers: `Conv1D`, `Conv2D`, `Conv3D`, `Conv2DTranspose`, etc.
- 池化层Pooling layers: `MaxPooling1D`, `MaxPooling2D`, `MaxPooling3D`, `AveragePooling1D`, etc.
- RNN 层: `GRU`, `LSTM`, `ConvLSTM2D`, etc.
- `BatchNormalization`, `Dropout`, `Embedding`, etc.
如果找不到所需的内容,可以通过创建自己的图层来扩展API。
所有图层都是`Layer`类的子类,并实现:
- 一个 `call` 方法,指定由层完成的计算。
- 一个`build`方法,它创建了图层的权重(请注意,这只是一种样式约定;您也可以在 `__init__` 中创建权重)。
要了解有关从头开始创建图层的更多信息,请查看该指南 [Guide to writing layers and models from scratch](https://tensorflow.google.cn/beta/guide/keras/custom_layers_and_models).
这是一个`Dense`层的简单实现:
```python
class CustomDense(layers.Layer):
def __init__(self, units=32):
super(CustomDense, self).__init__()
self.units = units
def build(self, input_shape):
self.w = self.add_weight(shape=(input_shape[-1], self.units),
initializer='random_normal',
trainable=True)
self.b = self.add_weight(shape=(self.units,),
initializer='random_normal',
trainable=True)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)
model = keras.Model(inputs, outputs)
```
如果希望自定义层支持序列化,还应定义 `get_config` 方法,该方法返回层实例的构造函数参数:
```python
class CustomDense(layers.Layer):
def __init__(self, units=32):
super(CustomDense, self).__init__()
self.units = units
def build(self, input_shape):
self.w = self.add_weight(shape=(input_shape[-1], self.units),
initializer='random_normal',
trainable=True)
self.b = self.add_weight(shape=(self.units,),
initializer='random_normal',
trainable=True)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
def get_config(self):
return {'units': self.units}
inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)
model = keras.Model(inputs, outputs)
config = model.get_config()
new_model = keras.Model.from_config(
config, custom_objects={'CustomDense': CustomDense})
```
或者,你也可以实现类方法 `from_config(cls, config)` ,它负责在给定配置字典的情况下重新创建一个层实例。`from_config` 的默认实现是:
```python
def from_config(cls, config):
return cls(**config)
```
## 11. 何时使用函数API
如何决定是使用Functional API创建新模型,还是直接将`Model`类继承?
通常,Functional API更高级,更容易和更安全使用,并且具有子模型不支持的许多功能。
但是,在创建不易表达为层的有向非循环图的模型时,模型子类化为您提供了更大的灵活性(例如,您无法使用Functional API实现Tree-RNN,您必须直接将`Model`子类化)。
### 11.1. 以下是Functional API的优势:
下面列出的属性对于Sequential模型也是如此(它们也是数据结构),但对于子类模型(Python字节码,而不是数据结构)则不然。
#### 11.1.1. 它不那么冗长。
No `super(MyClass, self).__init__(...)`, no `def call(self, ...):`, etc.
比较:
```python
inputs = keras.Input(shape=(32,))
x = layers.Dense(64, activation='relu')(inputs)
outputs = layers.Dense(10)(x)
mlp = keras.Model(inputs, outputs)
```
使用子类型:
```python
class MLP(keras.Model):
def __init__(self, **kwargs):
super(MLP, self).__init__(**kwargs)
self.dense_1 = layers.Dense(64, activation='relu')
self.dense_2 = layers.Dense(10)
def call(self, inputs):
x = self.dense_1(inputs)
return self.dense_2(x)
# Instantiate the model.
mlp = MLP()
# Necessary to create the model's state.
# The model doesn't have a state until it's called at least once.
_ = mlp(tf.zeros((1, 32)))
```
#### 11.1.2. 它在您定义模型时验证您的模型。
在Functional API中,您的输入规范(shape和dtype)是事先创建的(通过`Input`),每次调用一个图层时,图层都会检查传递给它的规范是否符合其假设,并且它会引发一个如果没有帮助错误消息。
这可以保证您可以运行使用Functional API构建的任何模型。所有调试(与收敛相关的调试除外)将在模型构建期间静态发生,而不是在执行时发生。这类似于编译器中的类型检查。
#### 11.1.3. 您的 Functional 模型是可绘图和可检查的。
您可以将模型绘制为图形,并且可以轻松访问此图中的中间节点 - 例如,提取和重用中间层的激活,如前面的示例中所示:
```python
features_list = [layer.output for layer in vgg19.layers]
feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)
```
#### 11.1.4. 您的 Functional 模型可以序列化或克隆。
因为 Functional 模型是一种数据结构而不是一段代码,所以它可以安全地序列化,并且可以保存为单个文件,允许您重新创建完全相同的模型,而无需访问任何原始代码。有关详细信息,请参阅我们的保存和序列化指南。
### 11.2. 以下是Functional API的弱点:
#### 11.2.1. 它不支持动态架构。
Functional API将模型视为图层的DAG。对于大多数深度学习体系结构都是如此,但并非全部:例如,递归网络或树RNN不遵循此假设,并且无法在Functional API中实现。
#### 11.2.2. 有时,您只需要从头开始编写所有内容。
在编写高级架构时,您可能希望执行“定义层的DAG”范围之外的事情:例如,您可能希望在模型实例上公开多个自定义训练和推理方法。这需要子类化。
---
为了更深入地了解Functional API和Model子类之间的差异,您可以阅读 [What are Symbolic and Imperative APIs in TensorFlow 2.0?](https://medium.com/tensorflow/what-are-symbolic-and-imperative-apis-in-tensorflow-2-0-dfccecb01021).
## 12. 混合和匹配不同的API样式
重要的是,在Functional API或Model子类化之间进行选择并不是一个二元决策,它将您限制为一类模型。tf.keras API中的所有模型都可以与每个模型进行交互,无论它们是顺序模型,功能模型还是从头开始编写的子类模型/层。
您始终可以使用Functional模型或Sequential模型作为子类 Model/Layer 的一部分:
```python
units = 32
timesteps = 10
input_dim = 5
# Define a Functional model
inputs = keras.Input((None, units))
x = layers.GlobalAveragePooling1D()(inputs)
outputs = layers.Dense(1, activation='sigmoid')(x)
model = keras.Model(inputs, outputs)
class CustomRNN(layers.Layer):
def __init__(self):
super(CustomRNN, self).__init__()
self.units = units
self.projection_1 = layers.Dense(units=units, activation='tanh')
self.projection_2 = layers.Dense(units=units, activation='tanh')
# Our previously-defined Functional model
self.classifier = model
def call(self, inputs):
outputs = []
state = tf.zeros(shape=(inputs.shape[0], self.units))
for t in range(inputs.shape[1]):
x = inputs[:, t, :]
h = self.projection_1(x)
y = h + self.projection_2(state)
state = y
outputs.append(y)
features = tf.stack(outputs, axis=1)
print(features.shape)
return self.classifier(features)
rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, timesteps, input_dim)))
```
(1, 10, 32)
相反,只要它实现了一个遵循以下模式之一的`call`方法,你就可以在Functional API中使用任何子类Layer或Model:
- `call(self, inputs, **kwargs)` 其中 `inputs` 是张量或张量的张量结构(例如张量列表),其中 `**kwargs` 是非张量参数(非输入)。
- `call(self, inputs, training=None, **kwargs)` 其中 `training` 是一个布尔值,表示该层是否应该在训练模式和推理模式下运行。
- `call(self, inputs, mask=None, **kwargs)` 其中 `mask` 是布尔掩码张量(例如对RNN有用)。
- `call(self, inputs, training=None, mask=None, **kwargs)` -- 当然,您可以同时具有屏蔽和特定于训练的行为。
此外,如果在自定义图层或模型上实现 `get_config` 方法,则使用它创建的功能模型仍将是可序列化和可克隆的。
这是一个快速示例,我们在Functional模型中使用从头开始编写的自定义RNN:
```python
units = 32
timesteps = 10
input_dim = 5
batch_size = 16
class CustomRNN(layers.Layer):
def __init__(self):
super(CustomRNN, self).__init__()
self.units = units
self.projection_1 = layers.Dense(units=units, activation='tanh')
self.projection_2 = layers.Dense(units=units, activation='tanh')
self.classifier = layers.Dense(1, activation='sigmoid')
def call(self, inputs):
outputs = []
state = tf.zeros(shape=(inputs.shape[0], self.units))
for t in range(inputs.shape[1]):
x = inputs[:, t, :]
h = self.projection_1(x)
y = h + self.projection_2(state)
state = y
outputs.append(y)
features = tf.stack(outputs, axis=1)
return self.classifier(features)
# Note that we specify a static batch size for the inputs with the `batch_shape`
# arg, because the inner computation of `CustomRNN` requires a static batch size
# (when we create the `state` zeros tensor).
inputs = keras.Input(batch_shape=(batch_size, timesteps, input_dim))
x = layers.Conv1D(32, 3)(inputs)
outputs = CustomRNN()(x)
model = keras.Model(inputs, outputs)
rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, 10, 5)))
```
这就是我们关于函数API的指南的全部内容!
现在,您已经拥有了一套用于构建深度学习模型的强大工具。
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-keras-functional.html](https://www.mashangxue123.com/tensorflow/tf2-guide-keras-functional.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/keras/functional](https://tensorflow.google.cn/beta/guide/keras/functional)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/functional.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/functional.md)
================================================
FILE: r2/guide/keras/overview.md
================================================
---
title: Keras概述:构建模型,输入数据,训练,评估,回调
tags: tensorflow2.0教程
categories: tensorflow2官方教程
top: 1999
abbrlink: tensorflow/tf2-guide-keras-overview
---
# Keras概述:构建模型,输入数据,训练,评估,回调,保存,分布(tensorflow2.0官方教程翻译)
Keras 是一个用于构建和训练深度学习模型的高阶API。它可用于快速设计原型、高级研究和生产,具有以下三个主要优势:
* 方便用户使用
Keras 具有针对常见用例做出优化的简单而一致的界面。它可针对用户错误提供切实可行的清晰反馈。
* 模块化和可组合
将可配置的构造块连接在一起就可以构建 Keras 模型,并且几乎不受限制。
* 易于扩展
可以编写自定义构造块以表达新的研究创意,并且可以创建新层、损失函数并开发先进的模型。
## 1. 导入 tf.keras
`tf.keras` 是 TensorFlow 对 [Keras API 规范](https://keras.io)的实现。这是一个用于构建和训练模型的高阶 API,包含对 TensorFlow 特定功能(例如[eager execution](https://tensorflow.google.cn/guide/keras#eager_execution)、[`tf.data` 管道](https://tensorflow.google.cn/api_docs/python/tf/data)和 [Estimators](https://tensorflow.google.cn/guide/estimators))的顶级支持。 `tf.keras` 使 TensorFlow 更易于使用,并且不会牺牲灵活性和性能。
首先,导入 `tf.keras` 以设置 TensorFlow 程序:
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
from tensorflow import keras
```
`tf.keras` 可以运行任何与 Keras 兼容的代码,但请注意:
* 最新版 TensorFlow 中的 `tf.keras` 版本可能与 PyPI 中的最新 keras 版本不同。请查看 `tf.keras.version`。
* [保存模型的权重](#weights_only)时,`tf.keras` 默认采用检查点格式。请传递 ` save_format='h5' `以使用 HDF5。
## 2. 构建简单的模型
### 2.1. 序列模型
在 Keras 中,您可以通过组合层来构建模型。模型(通常)是由层构成的图。最常见的模型类型是层的堆叠:`tf.keras.Sequential` 模型。
要构建一个简单的全连接网络(即多层感知器),请运行以下代码:
```python
from tensorflow.keras import layers
model = tf.keras.Sequential()
# 向模型添加一个64单元的密集连接层:
model.add(layers.Dense(64, activation='relu'))
# 加上另一个:
model.add(layers.Dense(64, activation='relu'))
# 添加一个包含10个输出单位的softmax层:
model.add(layers.Dense(10, activation='softmax'))
```
您可以找到有关如何使用Sequential模型的完整简短示例 [here](https://github.com/tensorflow/docs/blob/master/site/en/r2/tutorials/quickstart/beginner.ipynb).
要了解如何构建比Sequential模型更高级的模型,请参阅:
- [Guide to the Keras Functional](https://tensorflow.google.cn/beta/guide/keras/functional)
- [Guide to writing layers and models from scratch with subclassing](https://tensorflow.google.cn/beta/guide/keras/custom_layers_and_models)
### 2.2. 配置层
我们可以使用很多 `tf.keras.layers`,它们具有一些相同的构造函数参数:
* `activation`:设置层的激活函数。此参数由内置函数的名称指定,或指定为可调用对象。默认情况下,系统不会应用任何激活函数。
* `kernel_initializer` 和 `bias_initializer`:创建层权重(核和偏差)的初始化方案。此参数是一个名称或可调用对象,默认为 "Glorot uniform" 初始化器。
* `kernel_regularizer` 和 `bias_regularizer`:应用层权重(核和偏差)的正则化方案,例如 L1 或 L2 正则化。默认情况下,系统不会应用正则化函数。
以下代码使用构造函数参数实例化 `tf.keras.layers. Dense` 层:
```python
# 创建一个sigmoid层:
layers.Dense(64, activation='sigmoid')
# 或者使用下面的代码创建:
layers.Dense(64, activation=tf.keras.activations.sigmoid)
# 将具有因子0.01的L1正则化的线性层应用于核矩阵:
layers.Dense(64, kernel_regularizer=tf.keras.regularizers.l1(0.01))
# 将L2正则化系数为0.01的线性层应用于偏置向量:
layers.Dense(64, bias_regularizer=tf.keras.regularizers.l2(0.01))
# 一个内核初始化为随机正交矩阵的线性层:
layers.Dense(64, kernel_initializer='orthogonal')
# 偏置矢量初始化为2.0s的线性层:
layers.Dense(64, bias_initializer=tf.keras.initializers.Constant(2.0))
```
## 3. 训练和评估
### 3.1. 设置训练流程
构建好模型后,通过调用 `compile` 方法配置该模型的学习流程:
```python
model = tf.keras.Sequential([
# 向模型添加一个64单元的密集连接层:
layers.Dense(64, activation='relu', input_shape=(32,)),
# 加上另一个:
layers.Dense(64, activation='relu'),
# 添加具有10个输出单位的softmax层:
layers.Dense(10, activation='softmax')])
model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
```
`tf.keras.Model.compile` 采用三个重要参数:
* `optimizer`:此对象会指定训练过程。从`tf.keras.optimizers` 模块向其传递优化器实例,例如 `tf.keras.optimizers.Adam` 、`tf.keras.optimizers.SGD` 。如果您只想使用默认参数,还可以通过字符串指定优化器,例如'adam'或'sgd'。
* `loss`:要在优化期间最小化的函数。常见选择包括均方误差 (`mse`)、`categorical_crossentropy` 和 `binary_crossentropy`。损失函数由名称或通过从 `tf.keras.losses` 模块传递可调用对象来指定。
* `metrics`:用于监控训练。它们是 `tf.keras.metrics` 模块中的字符串名称或可调用对象。
* 此外,为了确保模型能够热切地进行训练和评估,您可以确保将`run_eagerly=True` 作为参数进行编译。
以下代码展示了配置模型以进行训练的几个示例:
```python
# 配置均方误差回归模型。
model.compile(optimizer=tf.keras.optimizers.Adam(0.01),
loss='mse', # 均方误差
metrics=['mae']) # 平均绝对误差
# 为分类分类配置一个模型
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.01),
loss=tf.keras.losses.CategoricalCrossentropy(),
metrics=[tf.keras.metrics.CategoricalAccuracy()])
```
### 3.2. 输入 NumPy 数据
对于小型数据集,请使用内存中的[NumPy](https://www.numpy.org/)数组训练和评估模型。使用 fit 方法使模型与训练数据“拟合”:
```python
import numpy as np
data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))
model.fit(data, labels, epochs=10, batch_size=32)
```
```
...
Epoch 10/10
1000/1000 [==============================] - 0s 82us/sample - loss: 11.4075 - categorical_accuracy: 0.1690
```
`tf.keras.Model.fit` 采用三个重要参数:
* `epochs`:以周期为单位进行训练。一个周期是对整个输入数据的一次迭代(以较小的批次完成迭代)。
* `batch_size`:当传递 NumPy 数据时,模型将数据分成较小的批次,并在训练期间迭代这些批次。此整数指定每个批次的大小。请注意,如果样本总数不能被批次大小整除,则最后一个批次可能更小。
* `validation_data`:在对模型进行原型设计时,您需要轻松监控该模型在某些验证数据上达到的效果。传递此参数(输入和标签元组)可以让该模型在每个周期结束时以推理模式显示所传递数据的损失和指标。
下面是使用 `validation_data` 的示例:
```python
import numpy as np
data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))
val_data = np.random.random((100, 32))
val_labels = np.random.random((100, 10))
model.fit(data, labels, epochs=10, batch_size=32,
validation_data=(val_data, val_labels))
```
```
Train on 1000 samples, validate on 100 samples
...
Epoch 10/10
1000/1000 [==============================] - 0s 93us/sample - loss: 11.5019 - categorical_accuracy: 0.1220 - val_loss: 11.5879 - val_categorical_accuracy: 0.0800
<tensorflow.python.keras.callbacks.History at 0x7fe0642970b8>
```
### 3.3. 输入 tf.data 数据集
使用 [Datasets API](https://tensorflow.google.cn/guide/datasets) 可扩展为大型数据集或多设备训练。将 `tf.data.Dataset` 实例传递到 `fit` 方法:
```python
# 实例化玩具数据集实例:
dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32)
# 在数据集上调用`fit`时,不要忘记指定`steps_per_epoch`。
model.fit(dataset, epochs=10, steps_per_epoch=30)
```
输出:
```
Epoch 1/10
30/30 [==============================] - 0s 7ms/step - loss: 11.4902 - categorical_accuracy: 0.1094
```
在上方代码中,`fit` 方法使用了 `steps_per_epoch` 参数(表示模型在进入下一个周期之前运行的训练步数)。由于 `Dataset` 会生成批次数据,因此该代码段不需要 `batch_size`。
数据集也可用于验证:
```python
dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32)
val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_labels))
val_dataset = val_dataset.batch(32)
model.fit(dataset, epochs=10,
validation_data=val_dataset)
```
```
...
Epoch 10/10
32/32 [==============================] - 0s 4ms/step - loss: 11.4778 - categorical_accuracy: 0.1560 - val_loss: 11.6653 - val_categorical_accuracy: 0.1300
<tensorflow.python.keras.callbacks.History at 0x7fdfd8329d30>
```
### 3.4. 评估和预测
`tf.keras.Model.evaluate`和`tf.keras.Model.predict`方法可以使用NumPy数据和`tf.data.Dataset`。
要评估所提供数据的推理模式损失和指标,请运行以下代码:
```python
data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))
model.evaluate(data, labels, batch_size=32)
model.evaluate(dataset, steps=30)
```
```
1000/1000 [==============================] - 0s 72us/sample - loss: 11.5580 - categorical_accuracy: 0.0960
30/30 [==============================] - 0s 2ms/step - loss: 11.4651 - categorical_accuracy: 0.1594
[11.465100129445394, 0.159375]
```
要在所提供数据(采用 NumPy 数组形式)的推理中预测最后一层的输出,请运行以下代码:
```python
result = model.predict(data, batch_size=32)
print(result.shape)
```
```
(1000, 10)
```
有关训练和评估的完整指南,包括如何从头开始编写自定义训练循环,请参阅[训练和评估指南](https://tensorflow.google.cn/beta/guide/keras/training_and_evaluation)。
## 4. 构建高级模型
### 4.1. 函数式 API
`tf.keras.Sequential` 模型是层的简单堆叠,无法表示任意模型。使用 [Keras 函数式 API](https://tensorflow.google.cn/beta/guide/keras/functional) 可以构建复杂的模型拓扑,例如:
* 多输入模型,
* 多输出模型,
* 具有共享层的模型(同一层被调用多次),
* 具有非序列数据流的模型(例如,剩余连接)。
使用函数式 API 构建的模型具有以下特征:
1. 层实例可调用并返回张量。
2. 输入张量和输出张量用于定义 `tf.keras.Model` 实例。
3. 此模型的训练方式和 `Sequential` 模型一样。
以下示例使用函数式 API 构建一个简单的全连接网络:
```python
inputs = tf.keras.Input(shape=(32,)) # 返回输入占位符
# 层实例可在张量上调用,并返回张量。
x = layers.Dense(64, activation='relu')(inputs)
x = layers.Dense(64, activation='relu')(x)
predictions = layers.Dense(10, activation='softmax')(x)
```
在给定输入和输出的情况下实例化模型。
```python
model = tf.keras.Model(inputs=inputs, outputs=predictions)
# compile步骤指定训练配置
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练5个周期
model.fit(data, labels, batch_size=32, epochs=5)
```
```
...
Epoch 5/5
1000/1000 [==============================] - 0s 81us/sample - loss: 11.4819 - accuracy: 0.1270
<tensorflow.python.keras.callbacks.History at 0x7fdfd820b898>
```
### 4.2. 模型子类化
通过对 `tf.keras.Model`进行子类化,并定义您自己的前向传播来构建完全可自定义的模型。在` __init__` 方法中创建层并将它们设置为类实例的属性。在 `call`方法中定义前向传播。
在启用 [eager execution](https://tensorflow.google.cn/beta/guide/eager) 时,模型子类化特别有用,因为可以强制写入前向传播。
*注意:为了确保正向传递总是强制运行,你必须在调用超级构造函数时设置`dynamic = True`*
要点:针对作业使用正确的 API。虽然模型子类化较为灵活,但代价是复杂性更高且用户出错率更高。如果可能,请首选函数式 API。
以下示例展示了使用自定义前向传播进行子类化的 `tf.keras.Model`,该传递不必强制运行:
```python
class MyModel(tf.keras.Model):
def __init__(self, num_classes=10):
super(MyModel, self).__init__(name='my_model')
self.num_classes = num_classes
# 在此处定义层。.
self.dense_1 = layers.Dense(32, activation='relu')
self.dense_2 = layers.Dense(num_classes, activation='sigmoid')
def call(self, inputs):
# 在这里定义你的前向传播
# 使用之前定义的层(在`__init__`中)
x = self.dense_1(inputs)
return self.dense_2(x)
```
实例化新模型类:
```python
model = MyModel(num_classes=10)
# The compile step specifies the training configuration.
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练5个周期
model.fit(data, labels, batch_size=32, epochs=5)
```
```
...
Epoch 5/5 1000/1000 [==============================] - 0s 74us/sample - loss: 11.4954 - accuracy: 0.1110
```
### 4.3. 自定义层
通过继承 `tf.keras.layers.Layer` 并实现以下方法来创建自定义层:
* `__init__`: (可选)定义此层要使用的子层
* `build`: 创建层的权重。使用 `add_weight` 方法添加权重。
* `call`: 定义前向传播。
* 或者,可以通过实现 `get_config` 方法和 `from_config` 类方法序列化层。
下面是一个自定义层的示例,它使用核矩阵实现输入的`matmul`:
```python
class MyLayer(layers.Layer):
def __init__(self, output_dim, **kwargs):
self.output_dim = output_dim
super(MyLayer, self).__init__(**kwargs)
def build(self, input_shape):
# Create a trainable weight variable for this layer.
self.kernel = self.add_weight(name='kernel',
shape=(input_shape[1], self.output_dim),
initializer='uniform',
trainable=True)
def call(self, inputs):
return tf.matmul(inputs, self.kernel)
def get_config(self):
base_config = super(MyLayer, self).get_config()
base_config['output_dim'] = self.output_dim
return base_config
@classmethod
def from_config(cls, config):
return cls(**config)
```
使用自定义层创建模型:
```python
model = tf.keras.Sequential([
MyLayer(10),
layers.Activation('softmax')])
# 训练配置
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 训练5个周期
model.fit(data, labels, batch_size=32, epochs=5)
```
了解有关从头开始创建新层和模型的更多信息,在[从头开始编写层和模型指南](https://tensorflow.google.cn/beta/guide/keras/custom_layers_and_models)。
## 5. 回调
回调是传递给模型的对象,用于在训练期间自定义该模型并扩展其行为。您可以编写自定义回调,也可以使用包含以下方法的内置 `tf.keras.callbacks`:
* `tf.keras.callbacks.ModelCheckpoint`: 定期保存模型的检查点。
* `tf.keras.callbacks.LearningRateScheduler`: 动态更改学习速率。
* `tf.keras.callbacks.EarlyStopping`:在验证效果不再改进时中断训练。
* `tf.keras.callbacks.TensorBoard`: 使用 [TensorBoard](https://tensorflow.google.cn/tensorboard) 监控模型的行为。
要使用 `tf.keras.callbacks.Callback`,请将其传递给模型的 `fit` 方法:
```python
callbacks = [
# 如果`val_loss`在2个以上的周期内停止改进,则进行中断训练
tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),
# 将TensorBoard日志写入`./logs`目录
tf.keras.callbacks.TensorBoard(log_dir='./logs')
]
model.fit(data, labels, batch_size=32, epochs=5, callbacks=callbacks,
validation_data=(val_data, val_labels))
```
```
Train on 1000 samples, validate on 100 samples
...
Epoch 5/5 1000/1000 [==============================] - 0s 76us/sample - loss: 11.4813 - accuracy: 0.1190 - val_loss: 11.5753 - val_accuracy: 0.1100 <tensorflow.python.keras.callbacks.History at 0x7fdfd12e7080>
```
## 6. 保存和恢复
### 6.1. 仅限权重
使用 `tf.keras.Model.save_weights`保存并加载模型的权重:
```python
model = tf.keras.Sequential([
layers.Dense(64, activation='relu', input_shape=(32,)),
layers.Dense(10, activation='softmax')])
model.compile(optimizer=tf.keras.optimizers.Adam(0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
```
```
# 将权重保存到TensorFlow检查点文件
model.save_weights('./weights/my_model')
# 恢复模型的状态,这需要具有相同架构的模型。
model.load_weights('./weights/my_model')
```
默认情况下,会以 [TensorFlow 检查点](https://tensorflow.google.cn/beta/guide/checkpoints)文件格式保存模型的权重。权重也可以另存为 Keras HDF5 格式(Keras 多后端实现的默认格式):
```
# 将权重保存到HDF5文件
model.save_weights('my_model.h5', save_format='h5')
# 恢复模型的状态
model.load_weights('my_model.h5')
```
### 6.2. 仅限配置
可以保存模型的配置,此操作会对模型架构(不含任何权重)进行序列化。即使没有定义原始模型的代码,保存的配置也可以重新创建并初始化相同的模型。Keras 支持 JSON 和 YAML 序列化格式:
```python
# 将模型序列化为JSON格式
json_string = model.to_json()
json_string
```
```
'{"class_name": "Sequential", "config": {"layers": [{"class_name": "Dense", "config": {"units": 64, "activity_regularizer": null, "dtype": "float32",....... "backend": "tensorflow", "keras_version": "2.2.4-tf"}'
```
```python
import json
import pprint
pprint.pprint(json.loads(json_string))
```
```
{'backend': 'tensorflow', 'class_name': 'Sequential', 'config': {'layers': [{'class_name': 'Dense', 'config': {'activation': 'relu', 'activity_regularizer': None, '......'keras_version': '2.2.4-tf'}
```
更多运行的输出内容请看英文版https://tensorflow.google.cn/beta/guide/keras/overview
从 json 重新创建模型(刚刚初始化)。
```python
fresh_model = tf.keras.models.model_from_json(json_string)
```
将模型序列化为YAML格式,要求您在导入TensorFlow之前安装pyyaml(命令:`pip install -q pyyaml`):
```
yaml_string = model.to_yaml()
print(yaml_string)
```
从YAML重新创建模型:
```python
fresh_model = tf.keras.models.model_from_yaml(yaml_string)
```
注意:子类化模型不可序列化,因为它们的架构由`call`方法正文中的 Python 代码定义。
### 6.3. 整个模型
整个模型可以保存到一个文件中,其中包含权重值、模型配置乃至优化器配置。这样,您就可以对模型设置检查点并稍后从完全相同的状态继续训练,而无需访问原始代码。
```python
# 创建一个简单的模型
model = tf.keras.Sequential([
layers.Dense(10, activation='softmax', input_shape=(32,)),
layers.Dense(10, activation='softmax')
])
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels, batch_size=32, epochs=5)
# 将整个模型保存到HDF5文件
model.save('my_model.h5')
# 重新创建完全相同的模型,包括权重和优化器
model = tf.keras.models.load_model('my_model.h5')
```
```
...
Epoch 5/5 1000/1000 [==============================] - 0s 76us/sample - loss: 11.4913 - accuracy: 0.0990
```
在[保存和序列化模型指南](https://tensorflow.google.cn/beta/guide/keras/saving_and_serializing)中,了解有关Keras模型的保存和序列化的更多信息。
## 7. Eager execution
[Eager execution](https://tensorflow.google.cn/guide/estimators) 是一种命令式编程环境,可立即评估操作。这不是Keras所必需的,但是由`tf.keras`支持,对于检查程序和调试很有用。
所有 `tf.keras` 模型构建 API 都与 Eager Execution 兼容。虽然可以使用 `Sequential` 和函数式 API,但 Eager Execution 对模型子类化和构建自定义层特别有用。与通过组合现有层来创建模型的 API 不同,函数式 API 要求您编写前向传播代码。
请参阅 [Eager Execution 指南](https://tensorflow.google.cn/guide/eager#build_a_model),了解将 Keras 模型与自定义训练循环和 [tf.GradientTape](https://tensorflow.google.cn/api_docs/python/tf/GradientTape) 搭配使用的示例 [here](https://github.com/tensorflow/docs/blob/master/site/en/r2/tutorials/quickstart/advanced.ipynb).。
## 8. 分布
### 8.1. 多个 GPU
`tf.keras` 模型可以使用 `tf.distribute.Strategy`在多个 GPU 上运行。此 API 在多个 GPU 上提供分布式训练,几乎不需要更改现有代码。
目前,`tf.distribute.MirroredStrategy`是唯一受支持的分布策略。`MirroredStrategy` 通过在一台机器上使用规约在同步训练中进行图内复制。要使用`distribute.Strategy`s,请在 `Strategy`'s `.scope()`中嵌套优化器实例化和模型构造和编译,然后训练模型。
以下示例在单个计算机上的多个GPU之间分发`tf.keras.Model`。
首先,在分布式策略范围内定义模型:
```python
strategy = tf.distribute.MirroredStrategy()
with strategy.scope():
model = tf.keras.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10,)))
model.add(layers.Dense(1, activation='sigmoid'))
optimizer = tf.keras.optimizers.SGD(0.2)
model.compile(loss='binary_crossentropy', optimizer=optimizer)
model.summary()
```
```
Model: "sequential_5"
_________________________________________________________________
Layer (type) Output Shape Param # =================================================================
dense_21 (Dense) (None, 16) 176 _________________________________________________________________
dense_22 (Dense) (None, 1) 17 =================================================================
Total params: 193 Trainable params: 193 Non-trainable params: 0
_________________________________________________________________
```
接下来,像往常一样训练模型数据:
```python
x = np.random.random((1024, 10))
y = np.random.randint(2, size=(1024, 1))
x = tf.cast(x, tf.float32)
dataset = tf.data.Dataset.from_tensor_slices((x, y))
dataset = dataset.shuffle(buffer_size=1024).batch(32)
model.fit(dataset, epochs=1)
```
```
32/32 [==============================] - 3s 82ms/step - loss: 0.7005 <tensorflow.python.keras.callbacks.History at 0x7fdfa057fb00>
```
有关更多信息,请参阅[TensorFlow中的分布式训练完整指南](https://tensorflow.google.cn/beta/guide/distribute_strategy)。
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-keras-overview.html](https://www.mashangxue123.com/tensorflow/tf2-guide-keras-overview.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/keras/overview](https://tensorflow.google.cn/beta/guide/keras/overview)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/overview.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/overview.md)
================================================
FILE: r2/guide/keras/training_and_evaluation.md
================================================
---
title: 使用 TensorFlow Keras 进行训练和评估
tags: tensorflow2.0教程
categories: tensorflow2官方教程
top: 1999
abbrlink: tensorflow/tf2-guide-keras-training_and_evaluation
---
# 使用TensorFlow Keras进行训练和评估 (tensorflow2.0官方教程翻译)
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-keras-training_and_evaluation.html](https://www.mashangxue123.com/tensorflow/tf2-guide-keras-training_and_evaluation.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/keras/training_and_evaluation](https://tensorflow.google.cn/beta/guide/keras/training_and_evaluation)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/training_and_evaluation.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/keras/training_and_evaluation.md)
本指南涵盖了TensorFlow 2.0在两种主要情况下的训练、评估和预测(推理)模型:
- 使用内置API进行训练和验证时(例如`model.fit()`, `model.evaluate()`, `model.predict()` )。这将在“使用内置的训练和评估循环”一节中讨论。
- 使用eager execution和 `GradientTape` 对象从头开始编写自定义循环时。这在 “从零开始编写您自己的训练和评估循环” 小节中有介绍。
一般来说,无论您是使用内置循环还是编写自己的循环,模型训练和评估在每种Keras模型(Sequential顺序模型、使用使用函数式API构建的模型以及通过模型子类从零开始编写的模型)中都严格按照相同的方式工作。
本指南不包括分布式训练。
## 设置
安装
```
pip install pydot
apt-get install graphviz
pip install tensorflow-gpu==2.0.0-alpha0
```
导入
```
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
tf.keras.backend.clear_session() # For easy reset of notebook state.
```
## 第一部分:使用内置训练和评估循环
将数据传递给模型的内置训练循环时,您应该使用Numpy数组(如果数据很小并且适合内存)或tf.data数据集对象。在接下来的几段中,我们将使用MNIST数据集作为Numpy数组,以演示如何使用优化器,损失和指标。
### API概述:第一个端到端示例
让我们考虑以下模型(这里,我们使用Functional API构建,但它也可以是顺序模型或子类模型):
```python
from tensorflow import keras
from tensorflow.keras import layers
inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
```
以下是典型的端到端工作流程的外观,包括训练,对原始训练数据生成的保留集的验证,以及最终对测试数据的评估:
```python
# Load a toy dataset for the sake of this example
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# Preprocess the data (these are Numpy arrays)
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255
# Reserve 10,000 samples for validation
x_val = x_train[-10000:]
y_val = y_train[-10000:]
x_train = x_train[:-10000]
y_train = y_train[:-10000]
# Specify the training configuration (optimizer, loss, metrics)
model.compile(optimizer=keras.optimizers.RMSprop(), # Optimizer
# Loss function to minimize
loss=keras.losses.SparseCategoricalCrossentropy(),
# List of metrics to monitor
metrics=[keras.metrics.SparseCategoricalAccuracy()])
# Train the model by slicing the data into "batches"
# of size "batch_size", and repeatedly iterating over
# the entire dataset for a given number of "epochs"
print('# Fit model on training data')
history = model.fit(x_train, y_train,
batch_size=64,
epochs=3,
# We pass some validation for
# monitoring validation loss and metrics
# at the end of each epoch
validation_data=(x_val, y_val))
# The returned "history" object holds a record
# of the loss values and metric values during training
print('\nhistory dict:', history.history)
# Evaluate the model on the test data using `evaluate`
print('\n# Evaluate on test data')
results = model.evaluate(x_test, y_test, batch_size=128)
print('test loss, test acc:', results)
# Generate predictions (probabilities -- the output of the last layer)
# on new data using `predict`
print('\n# Generate predictions for 3 samples')
predictions = model.predict(x_test[:3])
print('predictions shape:', predictions.shape)
```
### 指定损失,指标和优化程序
要训练合适的模型,您需要指定一个损失函数,一个优化器,以及可选的一些要监控的指标。
您将这些作为 `compile()` 方法的参数传递给模型:
```python
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
loss=keras.losses.SparseCategoricalCrossentropy(),
metrics=[keras.metrics.SparseCategoricalAccuracy()])
```
`metrics` 参数应该是一个列表(您的模型可以包含任意数量的度量标准)。
如果您的模型有多个输出,您可以为每个输出指定不同的损失和度量,并且您可以调整每个输出对模型总损失的贡献。
您将在“将数据传递到多输入、多输出模型”一节中找到更多关于此的详细信息。
注意,在很多情况下,损失和指标是通过字符串标识符指定的,作为一种快捷方式:
```python
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
loss='sparse_categorical_crossentropy',
metrics=['sparse_categorical_accuracy'])
```
为了以后的重用,我们将模型定义和编译步骤放在函数中;我们将在本指南的不同示例中多次调用它们。
```python
def get_uncompiled_model():
inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
return model
def get_compiled_model():
model = get_uncompiled_model()
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
loss='sparse_categorical_crossentropy',
metrics=['sparse_categorical_accuracy'])
return model
```
#### 许多内置的优化器、损失和指标都是可用的
通常,您不必从头开始创建自己的损失,指标或优化器,因为您需要的可能已经是Keras API的一部分:
Optimizers优化器:
- `SGD()` (with or without momentum)
- `RMSprop()`
- `Adam()`
- etc.
Losses损失:
- `MeanSquaredError()`
- `KLDivergence()`
- `CosineSimilarity()`
- etc.
Metrics指标:
- `AUC()`
- `Precision()`
- `Recall()`
- etc.
#### 编写自定义损失和指标
如果您需要不属于API的指标,则可以通过继承Metric类轻松创建自定义指标。
您需要实现4种方法:
- `__init__(self)`, 您将在其中为指标创建状态变量
- `update_state(self, y_true, y_pred, sample_weight=None)`, 它使用目标`y_true`和模型预测`y_pred`来更新状态变量。
- `result(self)`, 它使用状态变量来计算最终结果。
- `reset_states(self)`, 它重新初始化度量的状态。
状态更新和结果计算是分开的(分别在`update_state()` 和 `result()`中)因为在某些情况下,结果计算可能非常昂贵,并且只能定期进行。
这是一个简单的例子,展示了如何实现一个 `CatgoricalTruePositives` 指标,它计算了正确分类为属于给定类的样本数量:
```python
class CatgoricalTruePositives(keras.metrics.Metric):
def __init__(self, name='categorical_true_positives', **kwargs):
super(CatgoricalTruePositives, self).__init__(name=name, **kwargs)
self.true_positives = self.add_weight(name='tp', initializer='zeros')
def update_state(self, y_true, y_pred, sample_weight=None):
y_pred = tf.argmax(y_pred)
values = tf.equal(tf.cast(y_true, 'int32'), tf.cast(y_pred, 'int32'))
values = tf.cast(values, 'float32')
if sample_weight is not None:
sample_weight = tf.cast(sample_weight, 'float32')
values = tf.multiply(values, sample_weight)
self.true_positives.assign_add(tf.reduce_sum(values))
def result(self):
return self.true_positives
def reset_states(self):
# The state of the metric will be reset at the start of each epoch.
self.true_positives.assign(0.)
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
loss=keras.losses.SparseCategoricalCrossentropy(),
metrics=[CatgoricalTruePositives()])
model.fit(x_train, y_train,
batch_size=64,
epochs=3)
```
#### 处理不符合标准签名的损失和指标
绝大多数损失和指标可以从`y_true`和`y_pred`计算,其中`y_pred`是模型的输出。但不是全部。例如,正则化损失可能仅需要激活层(在这种情况下没有目标),并且该激活可能不是模型输出。
在这种情况下,您可以从自定义图层的`call`方法中调用 `self.add_loss(loss_value)` 。这是一个添加活动正则化的简单示例(请注意,活动正则化是内置于所有Keras层中的 - 此层仅用于提供具体示例):
```python
class ActivityRegularizationLayer(layers.Layer):
def call(self, inputs):
self.add_loss(tf.reduce_sum(inputs) * 0.1)
return inputs # Pass-through layer.
inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
# Insert activity regularization as a layer
x = ActivityRegularizationLayer()(x)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
loss='sparse_categorical_crossentropy')
# The displayed loss will be much higher than before
# due to the regularization component.
model.fit(x_train, y_train,
batch_size=64,
epochs=1)
```
您可以执行相同的记录度量标准值:
```python
class MetricLoggingLayer(layers.Layer):
def call(self, inputs):
# The `aggregation` argument defines
# how to aggregate the per-batch values
# over each epoch:
# in this case we simply average them.
self.add_metric(keras.backend.std(inputs),
name='std_of_activation',
aggregation='mean')
return inputs # Pass-through layer.
inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
# Insert std logging as a layer.
x = MetricLoggingLayer()(x)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
model.compile(optimizer=keras.optimizers.RMSprop(learning_rate=1e-3),
loss='sparse_categorical_crossentropy')
model.fit(x_train, y_train,
batch_size=64,
epochs=1)
```
50000/50000 [==============================] - 4s 76us/sample - loss: 0.3366 - std_of_activation: 0.9773
在 [Functional API](https://tensorflow.google.cn/beta/guide/keras/functional) 中,您还可以调用 `model.add_loss(loss_tensor)`, 或 `model.add_metric(metric_tensor, name, aggregation)`。
这是一个简单的例子:
```python
inputs = keras.Input(shape=(784,), name='digits')
x1 = layers.Dense(64, activation='relu', name='dense_1')(inputs)
x2 = layers.Dense(64, activation='relu', name='dense_2')(x1)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x2)
model = keras.Model(inputs=inputs, outputs=outputs)
model.add_loss(tf.reduce_sum(x1) * 0.1)
model.add_metric(keras.backend.std(x1),
name='std_of_activation',
aggregation='mean')
model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
loss='sparse_categorical_crossentropy')
model.fit(x_train, y_train,
batch_size=64,
epochs=1)
```
50000/50000 [==============================] - 4s 80us/sample - loss: 2.5158 - std_of_activation: 0.0020
#### 自动设置验证保持集
在您看到的第一个端到端示例中,我们使用 `validation_data` 参数将Numpy数组 `(x_val, y_val)` 的元组传递给模型,以便在每个时期结束时评估验证损失和验证指标。
这是另一个选项:参数 `validation_split` 允许您自动保留部分训练数据以进行验证。参数值表示要为验证保留的数据的分数,因此应将其设置为大于0且小于1的数字。例如,`validation_split=0.2` 表示“使用20%的数据进行验证”,`validation_split=0.6` 表示“使用60%的数据进行验证”。
计算验证的方法是:在任何混洗之前,通过`fit`调用接收的数组的最后x%样本。
在使用Numpy数据进行训练时,您只能使用 `validation_split`。
```python
model = get_compiled_model()
model.fit(x_train, y_train, batch_size=64, validation_split=0.2, epochs=3)
```
输出
Train on 40000 samples, validate on 10000 samples
Epoch 1/3
40000/40000 [==============================] - 3s 82us/sample - loss: 0.3735 - sparse_categorical_accuracy: 0.8951 - val_loss: 0.2413 - val_sparse_categorical_accuracy: 0.9272
Epoch 2/3
40000/40000 [==============================] - 3s 82us/sample - loss: 0.1688 - sparse_categorical_accuracy: 0.9499 - val_loss: 0.1781 - val_sparse_categorical_accuracy: 0.9468
Epoch 3/3
40000/40000 [==============================] - 3s 79us/sample - loss: 0.1232 - sparse_categorical_accuracy: 0.9638 - val_loss: 0.1518 - val_sparse_categorical_accuracy: 0.9539
### 来自tf.data数据集的培训和评估
在过去的几段中,您已经了解了如何处理损失,度量和优化器,并且您已经看到,当您的数据作为Numpy数组传递时,如何在`fit`中使用`validation_data` 和 `validation_split` 参数
现在让我们看一下您的数据以tf.data数据集的形式出现的情况。
tf.data API是TensorFlow 2.0中的一组实用程序,用于以快速和可伸缩的方式加载和预处理数据。
有关创建数据集的完整指南,请参阅[the tf.data 文档](https://tensorflow.google.cn/versions/r2.0/api_docs/python/tf)。
您可以将数据集实例直接传递给方法 `fit()`, `evaluate()`, 和 `predict()`:
```python
model = get_compiled_model()
# First, let's create a training Dataset instance.
# For the sake of our example, we'll use the same MNIST data as before.
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
# Shuffle and slice the dataset.
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)
# Now we get a test dataset.
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, y_test))
test_dataset = test_dataset.batch(64)
# Since the dataset already takes care of batching,
# we don't pass a `batch_size` argument.
model.fit(train_dataset, epochs=3)
# You can also evaluate or predict on a dataset.
print('\n# Evaluate')
model.evaluate(test_dataset)
```
输出:
Epoch 1/3
782/782 [==============================] - 5s 7ms/step - loss: 0.3250 - sparse_categorical_accuracy: 0.9074
Epoch 2/3
782/782 [==============================] - 4s 6ms/step - loss: 0.1484 - sparse_categorical_accuracy: 0.9559
Epoch 3/3
782/782 [==============================] - 4s 5ms/step - loss: 0.1074 - sparse_categorical_accuracy: 0.9685
# Evaluate
157/157 [==============================] - 1s 3ms/step - loss: 0.1137 - sparse_categorical_accuracy: 0.9665
请注意,数据集在每个周期的末尾都会重置,因此可以重复使用下一个周期。
如果您只想从此数据集中对特定数量的批次运行训练,则可以传递 `steps_per_epoch` 参数,该参数指定在继续下一个周期之前使用此数据集运行模型的训练步数。
如果这样做,数据集不会在每个周期的末尾重置,而是我们只是继续绘制下一批。数据集最终会耗尽数据(除非它是一个无限循环的数据集)。
```python
model = get_compiled_model()
# Prepare the training dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)
# Only use the 100 batches per epoch (that's 64 * 100 samples)
model.fit(train_dataset.take(100), epochs=3)
```
Epoch 1/3
100/100 [==============================] - 1s 11ms/step - loss: 0.7733 - sparse_categorical_accuracy: 0.8067
Epoch 2/3
100/100 [==============================] - 0s 5ms/step - loss: 0.3706 - sparse_categorical_accuracy: 0.8922
Epoch 3/3
100/100 [==============================] - 1s 5ms/step - loss: 0.3379 - sparse_categorical_accuracy: 0.9011
#### 使用验证数据集
您可以将数据集实例作为`fit`中的`validation_data`参数传递:
```python
model = get_compiled_model()
# Prepare the training dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)
# Prepare the validation dataset
val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val))
val_dataset = val_dataset.batch(64)
model.fit(train_dataset, epochs=3, validation_data=val_dataset)
```
Epoch 1/3
782/782 [==============================] - 7s 8ms/step - loss: 0.3440 - sparse_categorical_accuracy: 0.9020 - val_loss: 0.1838 - val_sparse_categorical_accuracy: 0.9490
Epoch 2/3
782/782 [==============================] - 7s 9ms/step - loss: 0.1649 - sparse_categorical_accuracy: 0.9515 - val_loss: 0.1391 - val_sparse_categorical_accuracy: 0.9603
Epoch 3/3
782/782 [==============================] - 8s 10ms/step - loss: 0.1216 - sparse_categorical_accuracy: 0.9645 - val_loss: 0.1208 - val_sparse_categorical_accuracy: 0.9672
在每个周期结束时,模型将迭代验证数据集并计算验证损失和验证指标。
如果你想只在这个数据集中特定数量的批次上运行验证,你可以传递“validation_steps”参数,它指定了模型在中断验证并进入下一个周期之前,应该与验证数据集一起运行多少个验证步骤:
```python
model = get_compiled_model()
# Prepare the training dataset
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)
# Prepare the validation dataset
val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val))
val_dataset = val_dataset.batch(64)
model.fit(train_dataset, epochs=3,
# Only run validation using the first 10 batches of the dataset
# using the `validation_steps` argument
validation_data=val_dataset, validation_steps=10)
```
Epoch 1/3
782/782 [==============================] - 9s 12ms/step - loss: 0.3359 - sparse_categorical_accuracy: 0.9053 - val_loss: 0.3095 - val_sparse_categorical_accuracy: 0.9187
Epoch 2/3
782/782 [==============================] - 7s 9ms/step - loss: 0.1593 - sparse_categorical_accuracy: 0.9528 - val_loss: 0.2196 - val_sparse_categorical_accuracy: 0.9438
Epoch 3/3
782/782 [==============================] - 7s 9ms/step - loss: 0.1158 - sparse_categorical_accuracy: 0.9661 - val_loss: 0.1840 - val_sparse_categorical_accuracy: 0.9469
请注意,验证数据集将在每次使用后重置(这样您将始终评估从epoch到epoch的相同样本)。从数据集对象进行训练时,不支持参数validation_split(从训练数据生成保持集),因为此功能需要能够索引数据集的样本,这通常是数据集API无法实现的。
### 支持其他输入格式
除了Numpy数组和TensorFlow数据集之外,还可以使用Pandas数据帧或产生批量的Python生成器来训练Keras模型。
通常,如果数据很小并且适合内存,我们建议您使用Numpy输入数据,否则使用数据集。
### 使用样本加权和类权重
除了输入数据和目标数据之外,还可以在使用 `fit` 时将样本权重或类权重传递给模型:
- 从Numpy数据训练时:通过`sample_weight`和`class_weight`参数。
- 从数据集训练时:通过让数据集返回一个元组 `(input_batch, target_batch, sample_weight_batch)` .
"sample weights" 数组是一个数字数组,用于指定批处理中每个样本在计算总损失时应具有多少权重。它通常用于不平衡的分类问题(这个想法是为了给予很少见的类别更多的权重)。当使用的权重是1和0时,该数组可以用作损失函数的掩码(完全丢弃某些样本对总损失的贡献)。
"class weights" 字典是同一概念的更具体的实例:它将类索引映射到应该用于属于该类的样本的样本权重。例如,如果类“0”比数据中的类“1”少两倍,则可以使用 `class_weight={0: 1., 1: 0.5}`.
这是一个Numpy示例,我们使用类权重class weights或样本权重sample weights来更加重视 class #5 的正确分类(这是MNIST数据集中的数字“5”)。
```python
import numpy as np
class_weight = {0: 1., 1: 1., 2: 1., 3: 1., 4: 1.,
# Set weight "2" for class "5",
# making this class 2x more important
5: 2.,
6: 1., 7: 1., 8: 1., 9: 1.}
model.fit(x_train, y_train,
class_weight=class_weight,
batch_size=64,
epochs=4)
# Here's the same example using `sample_weight` instead:
sample_weight = np.ones(shape=(len(y_train),))
sample_weight[y_train == 5] = 2.
model = get_compiled_model()
model.fit(x_train, y_train,
sample_weight=sample_weight,
batch_size=64,
epochs=4)
```
Epoch 1/4
50000/50000 [==============================] - 4s 89us/sample - loss: 0.1040 - sparse_categorical_accuracy: 0.9715
.....
Epoch 4/4
50000/50000 [==============================] - 4s 83us/sample - loss: 0.1016 - sparse_categorical_accuracy: 0.9719
这是一个匹配的数据集示例:
```python
sample_weight = np.ones(shape=(len(y_train),))
sample_weight[y_train == 5] = 2.
# Create a Dataset that includes sample weights
# (3rd element in the return tuple).
train_dataset = tf.data.Dataset.from_tensor_slices(
(x_train, y_train, sample_weight))
# Shuffle and slice the dataset.
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)
model = get_compiled_model()
model.fit(train_dataset, epochs=3)
```
Epoch 1/3
782/782 [==============================] - 9s 11ms/step - loss: 0.3666 - sparse_categorical_accuracy: 0.9046
Epoch 2/3
782/782 [==============================] - 7s 9ms/step - loss: 0.1646 - sparse_categorical_accuracy: 0.9539
Epoch 3/3
782/782 [==============================] - 7s 9ms/step - loss: 0.1178 - sparse_categorical_accuracy: 0.9677
### 将数据传递到多输入,多输出模型
在前面的例子中,我们考虑的是一个带有单个输入的模型(形状为 `(764,)` 的张量)和单个输出(形状为 `(10,)` 的预测张量)。但是具有多个输入或输出的模型呢?
考虑下面的模型,它有一个形状为 `(32, 32, 3)` 的形状输入(即“(高度,宽度,通道)”)和形状为 `(None, 10)` 的时间序列输入(即“(时间步长,特征)”)。我们的模型将根据这些输入的组合计算两个输出:“得分”(形状为`(1,)`和5个类别(形状为`(10,)`)的概率分布。
```python
from tensorflow import keras
from tensorflow.keras import layers
image_input = keras.Input(shape=(32, 32, 3), name='img_input')
timeseries_input = keras.Input(shape=(None, 10), name='ts_input')
x1 = layers.Conv2D(3, 3)(image_input)
x1 = layers.GlobalMaxPooling2D()(x1)
x2 = layers.Conv1D(3, 3)(timeseries_input)
x2 = layers.GlobalMaxPooling1D()(x2)
x = layers.concatenate([x1, x2])
score_output = layers.Dense(1, name='score_output')(x)
class_output = layers.Dense(5, activation='softmax', name='class_output')(x)
model = keras.Model(inputs=[image_input, timeseries_input],
outputs=[score_output, class_output])
```
让我们绘制这个模型,这样你就可以清楚地看到我们在这里做的事情(请注意,图中显示的形状是批量形状,而不是每个样本的形状)。
```
keras.utils.plot_model(model, 'multi_input_and_output_model.png', show_shapes=True)
```

在编译时,我们可以通过将损失函数作为列表传递给不同的输出指定不同的损失:
```
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss=[keras.losses.MeanSquaredError(),
keras.losses.CategoricalCrossentropy()])
```
如果我们只将单个损失函数传递给模型,则相同的损失函数将应用于每个输出,这在这里是不合适的。
同样适用于指标:
```
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss=[keras.losses.MeanSquaredError(),
keras.losses.CategoricalCrossentropy()],
metrics=[[keras.metrics.MeanAbsolutePercentageError(),
keras.metrics.MeanAbsoluteError()],
[keras.metrics.CategoricalAccuracy()]])
```
由于我们为输出层指定了名称,因此我们还可以通过dict指定每个输出的损失和指标:
```python
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={'score_output': keras.losses.MeanSquaredError(),
'class_output': keras.losses.CategoricalCrossentropy()},
metrics={'score_output': [keras.metrics.MeanAbsolutePercentageError(),
keras.metrics.MeanAbsoluteError()],
'class_output': [keras.metrics.CategoricalAccuracy()]})
```
如果您有超过2个输出,我们建议使用显式名称和dicts。
可以给不同的输出特定损失赋予不同的权重(例如,可能希望通过使用`loss_weight`参数赋予2x类损失的重要性来保留我们示例中的“得分”损失特权:
```python
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={'score_output': keras.losses.MeanSquaredError(),
'class_output': keras.losses.CategoricalCrossentropy()},
metrics={'score_output': [keras.metrics.MeanAbsolutePercentageError(),
keras.metrics.MeanAbsoluteError()],
'class_output': [keras.metrics.CategoricalAccuracy()]},
loss_weight={'score_output': 2., 'class_output': 1.})
```
您还可以选择不计算某些输出的损失,如果这些输出用于预测但不用于训练:
```python
# List loss version
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss=[None, keras.losses.CategoricalCrossentropy()])
# Or dict loss version
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss={'class_output': keras.losses.CategoricalCrossentropy()})
```
将数据传递给`fit`中的多输入或多输出模型的工作方式与在`compile`中指定损失函数的方式类似:
你可以传递Numpy数组列表(1:1映射到接收到损失函数的输出)或者将输出名称映射到Numpy训练数据数组。
```python
model.compile(
optimizer=keras.optimizers.RMSprop(1e-3),
loss=[keras.losses.MeanSquaredError(),
keras.losses.CategoricalCrossentropy()])
# Generate dummy Numpy data
img_data = np.random.random_sample(size=(100, 32, 32, 3))
ts_data = np.random.random_sample(size=(100, 20, 10))
score_targets = np.random.random_sample(size=(100, 1))
class_targets = np.random.random_sample(size=(100, 5))
# Fit on lists
model.fit([img_data, ts_data], [score_targets, class_targets],
batch_size=32,
epochs=3)
# Alernatively, fit on dicts
model.fit({'img_input': img_data, 'ts_input': ts_data},
{'score_output': score_targets, 'class_output': class_targets},
batch_size=32,
epochs=3)
```
这是数据集用例:类似于我们为Numpy数组所做的,数据集应该返回一个dicts元组。
```python
train_dataset = tf.data.Dataset.from_tensor_slices(
({'img_input': img_data, 'ts_input': ts_data},
{'score_output': score_targets, 'class_output': class_targets}))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(64)
model.fit(train_dataset, epochs=3)
```
### 使用回调Using callbacks
Keras中的回调是在训练期间(在周期开始时,批处理结束时,周期结束时等)在不同点调用的对象,可用于实现以下行为:
- 在训练期间的不同时间点进行验证(超出内置的每个时期验证)
- 定期检查模型或超过某个精度阈值
- 在训练时改变模型的学习率似乎是平稳的
- 在训练时对顶层进行微调似乎是平稳的
- 在训练结束或超出某个性能阈值时发送电子邮件或即时消息通知
- Etc.
回调可以作为列表传递给你对 `fit` 的调用:
```python
model = get_compiled_model()
callbacks = [
keras.callbacks.EarlyStopping(
# Stop training when `val_loss` is no longer improving
monitor='val_loss',
# "no longer improving" being defined as "no better than 1e-2 less"
min_delta=1e-2,
# "no longer improving" being further defined as "for at least 2 epochs"
patience=2,
verbose=1)
]
model.fit(x_train, y_train,
epochs=20,
batch_size=64,
callbacks=callbacks,
validation_split=0.2)
```
#### 许多内置回调都可用
- `ModelCheckpoint`: 定期保存模型。
- `EarlyStopping`: 当训练不再改进验证指标时停止训练。
- `TensorBoard`: 定期编写可在TensorBoard中显示的模型日志(更多细节见“可视化”)。
- `CSVLogger`: 将丢失和指标数据丢失到CSV文件。
- etc.
#### 编写自己的回调
您可以通过扩展基类 `keras.callbacks.Callback` 来创建自定义回调。回调可以通过类属性 `self.model` 访问其关联的模型。
以下是在训练期间保存每批损失值列表的简单示例:
```python
class LossHistory(keras.callbacks.Callback):
def on_train_begin(self, logs):
self.losses = []
def on_batch_end(self, batch, logs):
self.losses.append(logs.get('loss'))
```
### 检查点模型
当您在相对较大的数据集上训练模型时,以频繁的间隔保存模型的检查点至关重要。
实现此目的的最简单方法是使用 `ModelCheckpoint` 回调:
```python
model = get_compiled_model()
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath='mymodel_{epoch}.h5',
# Path where to save the model
# The two parameters below mean that we will overwrite
# the current checkpoint if and only if
# the `val_loss` score has improved.
save_best_only=True,
monitor='val_loss',
verbose=1)
]
model.fit(x_train, y_train,
epochs=3,
batch_size=64,
callbacks=callbacks,
validation_split=0.2)
```
您也可以编写自己的回调来保存和恢复模型。
有关序列化和保存的完整指南,请参见[保存和序列化模型指南](https://tensorflow.google.cn/beta/guide/keras/saving_and_serializing)。
### 使用学习率计划
在训练深度学习模型时,一个常见的模式是随着训练的进展逐步减少学习。这通常被称为“学习速度衰减”。
学习衰减计划可以是静态的(预先固定,作为当前周期或当前批处理索引的函数),也可以是动态的(响应模型当前的行为,特别是验证损失)。
#### 将计划传递给优化程序
您可以通过在优化程序中将计划对象作为learning_rate参数传递,轻松使用静态学习速率衰减计划:
```python
initial_learning_rate = 0.1
lr_schedule = keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate,
decay_steps=100000,
decay_rate=0.96,
staircase=True)
optimizer = keras.optimizers.RMSprop(learning_rate=lr_schedule)
```
有几个内置的schedule表: `ExponentialDecay`, `PiecewiseConstantDecay`, `PolynomialDecay`, and `InverseTimeDecay`.
#### 使用回调来实现动态学习速率计划
使用这些schedule对象无法实现动态学习速率计划(例如,当验证损失不再改善时降低学习速率),因为优化器无法访问验证指标。
然而,回调确实可以访问所有指标,包括验证指标!
因此,可以通过使用回调函数来修改优化器上的当前学习率来实现这种模式。
事实上,它甚至内置在 `ReduceLROnPlateau` 回调函数中。
### 在训练期间可视化损失和度量
在训练期间密切关注你的模型的最好方法是使用 [TensorBoard](https://www.tensorflow.org/tensorboard) ,这是一个基于浏览器的应用程序,你可以在本地运行,它为你提供:
- 实时绘制损失和训练和评估指标
- (可选)可视化图层激活的直方图
- (可选)由“嵌入”图层学习的嵌入空间的三维可视化
如果您已经使用pip安装了TensorFlow,那么您应该能够从命令行启动TensorBoard:
```
tensorboard --logdir=/full_path_to_your_logs
```
#### 使用TensorBoard回调
在Keras模型和 `fit` 方法中使用TensorBoard的最简单方法是TensorBoard回调。
在最简单的情况下,只需指定回写日志的位置,就可以了:
```python
tensorboard_cbk = keras.callbacks.TensorBoard(log_dir='/full_path_to_your_logs')
model.fit(dataset, epochs=10, callbacks=[tensorboard_cbk])
```
TensorBoard回调有许多有用的选项,包括是否记录嵌入,直方图以及写入日志的频率:
```python
keras.callbacks.TensorBoard(
log_dir='/full_path_to_your_logs',
histogram_freq=0, # How often to log histogram visualizations
embeddings_freq=0, # How often to log embedding visualizations
update_freq='epoch') # How often to write logs (default: once per epoch)
```
## 第二部分:从头开始编写自己的训练和评估循环
如果你想要训练和评估循环的级别低于 `fit()` 和 `evaluate()` 提供的的级别,你应该自己编写。它实际上非常简单!但是你应该准备好自己做更多的调试。
### 使用GradientTape:第一个端到端的例子
在“GradientTape”范围内调用模型使您可以根据损失值检索图层的可训练权重的梯度。使用优化器实例,您可以使用这些梯度来更新这些变量(可以使用`model.trainable_weights`检索)。
让我们重用第一部分中的初始MNIST模型,让我们使用带有自定义训练循环的小批量梯度训练它。
```python
# Get the model.
inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
# Instantiate an optimizer.
optimizer = keras.optimizers.SGD(learning_rate=1e-3)
# Instantiate a loss function.
loss_fn = keras.losses.SparseCategoricalCrossentropy()
# Prepare the training dataset.
batch_size = 64
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(batch_size)
# Iterate over epochs.
for epoch in range(3):
print('Start of epoch %d' % (epoch,))
# Iterate over the batches of the dataset.
for step, (x_batch_train, y_batch_train) in enumerate(train_dataset):
# Open a GradientTape to record the operations run
# during the forward pass, which enables autodifferentiation.
with tf.GradientTape() as tape:
# Run the forward pass of the layer.
# The operations that the layer applies
# to its inputs are going to be recorded
# on the GradientTape.
logits = model(x_batch_train) # Logits for this minibatch
# Compute the loss value for this minibatch.
loss_value = loss_fn(y_batch_train, logits)
# Use the gradient tape to automatically retrieve
# the gradients of the trainable variables with respect to the loss.
grads = tape.gradient(loss_value, model.trainable_weights)
# Run one step of gradient descent by updating
# the value of the variables to minimize the loss.
optimizer.apply_gradients(zip(grads, model.trainable_weights))
# Log every 200 batches.
if step % 200 == 0:
print('Training loss (for one batch) at step %s: %s' % (step, float(loss_value)))
print('Seen so far: %s samples' % ((step + 1) * 64))
```
### 指标的低级处理
让我们添加指标。您可以很容易地在这样的训练循环中重用内置的指标(或您编写的自定义指标)。这是流程:
- 在循环开始时实例化度量标准
- 每批后调用 `metric.update_state()`
- 当需要显示度量的当前值时,调用`metric.result()`
- 当需要清除度量的状态时(通常在一个周期的末尾),调用`metric.reset_states()`
让我们使用这些知识在每个周期结束时计算验证数据的 `SparseCategoricalAccuracy` :
```python
# Get model
inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
# Instantiate an optimizer to train the model.
optimizer = keras.optimizers.SGD(learning_rate=1e-3)
# Instantiate a loss function.
loss_fn = keras.losses.SparseCategoricalCrossentropy()
# Prepare the metrics.
train_acc_metric = keras.metrics.SparseCategoricalAccuracy()
val_acc_metric = keras.metrics.SparseCategoricalAccuracy()
# Prepare the training dataset.
batch_size = 64
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_dataset = train_dataset.shuffle(buffer_size=1024).batch(batch_size)
# Prepare the validation dataset.
val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val))
val_dataset = val_dataset.batch(64)
# Iterate over epochs.
for epoch in range(3):
print('Start of epoch %d' % (epoch,))
# 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)
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(y_batch_train, logits)
# Log every 200 batches.
if step % 200 == 0:
print('Training loss (for one batch) at step %s: %s' % (step, float(loss_value)))
print('Seen so far: %s samples' % ((step + 1) * 64))
# Display metrics at the end of each epoch.
train_acc = train_acc_metric.result()
print('Training acc over epoch: %s' % (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)
# Update val metrics
val_acc_metric(y_batch_val, val_logits)
val_acc = val_acc_metric.result()
val_acc_metric.reset_states()
print('Validation acc: %s' % (float(val_acc),))
```
### 低水平处理额外损失
您在上一节中看到,通过在`call`方法中调用 `self.add_loss(value)` ,可以通过图层添加正则化损失。
在一般情况下,您需要在自定义训练循环中考虑这些损失(除非您自己编写模型并且您已经知道它不会造成这样的损失)。
回想一下上一节的这个例子,它的特点是一个层会产生正则化损失:
```python
class ActivityRegularizationLayer(layers.Layer):
def call(self, inputs):
self.add_loss(1e-2 * tf.reduce_sum(inputs))
return inputs
inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
# Insert activity regularization as a layer
x = ActivityRegularizationLayer()(x)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
```
当您调用模型时,如下所示:
```python
logits = model(x_train)
```
它在前向传递期间产生的损失被添加到 `model.losses` 属性中:
```python
logits = model(x_train[:64])
print(model.losses)
```
跟踪损失首先在模型 `__call__` 开始时清除,因此您只能看到在这一次前进过程中产生的损失。例如,重复调用模型然后查询 `losses` 只显示最后一次调用期间创建的最新损失:
```python
logits = model(x_train[:64])
logits = model(x_train[64: 128])
logits = model(x_train[128: 192])
print(model.losses)
```
要在训练期间考虑这些损失,您所要做的就是修改训练循环,将 `sum(model.losses)` 添加到您的总损失中:
```python
optimizer = keras.optimizers.SGD(learning_rate=1e-3)
for epoch in range(3):
print('Start of epoch %d' % (epoch,))
for step, (x_batch_train, y_batch_train) in enumerate(train_dataset):
with tf.GradientTape() as tape:
logits = model(x_batch_train)
loss_value = loss_fn(y_batch_train, logits)
# Add extra losses created during this forward pass:
loss_value += sum(model.losses)
grads = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(zip(grads, model.trainable_weights))
# Log every 200 batches.
if step % 200 == 0:
print('Training loss (for one batch) at step %s: %s' % (step, float(loss_value)))
print('Seen so far: %s samples' % ((step + 1) * 64))
```
那是拼图的最后一块!你已经到了本指南的末尾。
现在您已经了解了有关使用内置训练循环以及从头开始编写自己的知识的所有信息。
================================================
FILE: r2/guide/migration_guide.md
================================================
---
title: 将 TF1.x 代码迁移到 TensorFlow 2.0
categories: tensorflow2官方教程
tags: tensorflow2.0教程
top: 1903
abbrlink: tensorflow/tf2-guide-migration_guide
---
# 将 TF1.x 代码迁移到 TensorFlow 2.0(tensorflow2.0官方教程翻译)
在TensorFlow 2.0中,仍然可以运行未经修改的1.x代码(contrib除外):
```python
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
```
但是,这并不能让您利用TensorFlow2.0中的许多改进。本指南将帮助您升级代码,使其更简单、更高效、更易于维护。
## 自动转换脚本
第一步是尝试运行[升级脚本](https://tensorflow.google.cn/beta/guide/upgrade).
这将在将您的代码升级到TensorFlow 2.0时执行初始步骤。但是它不能使您的代码适合TensorFlowF 2.0。您的代码仍然可以使用`tf.compat.v1` 接口来访问占位符,会话,集合和其他1.x样式的功能。
## 使代码2.0原生化
本指南将介绍将TensorFlow 1.x代码转换为TensorFlow 2.0的几个示例。这些更改将使您的代码利用性能优化和简化的API调用。
在每一种情况下,模式是:
### 1. 替换`tf.Session.run`调用
每个`tf.Session.run`调用都应该被Python函数替换。
* `feed_dict`和`tf.placeholder'成为函数参数。
* `fetches`成为函数的返回值。
您可以使用标准Python工具(如`pdb`)逐步调试和调试函数
如果您对它的工作感到满意,可以添加一个`tf.function`装饰器,使其在图形模式下高效运行。有关其工作原理的更多信息,请参阅[Autograph Guide](https://tensorflow.google.cn/beta/guide/autograph)。
### 2. 使用Python对象来跟踪变量和损失
使用`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`集合。
有关详细信息,请参阅[keras指南](https://tensorflow.google.cn/beta/guide/keras)。
警告:许多`tf.compat.v1`符号隐式使用全局集合。
### 3. 升级您的训练循环
使用适用于您的用例的最高级API。首选`tf.keras.Model.fit`构建自己的训练循环。
如果您编写自己的训练循环,这些高级函数可以管理很多可能容易遗漏的低级细节。例如,它们会自动收集正则化损失,并在调用模型时设置`training = True`参数。
### 4. 升级数据输入管道
使用`tf.data`数据集进行数据输入。这些对象是高效的,富有表现力的,并且与张量流很好地集成。
它们可以直接传递给`tf.keras.Model.fit`方法。
```python
model.fit(dataset, epochs=5)
```
它们可以直接在标准Python上迭代:
```python
for example_batch, label_batch in dataset:
break
```
## 转换模型
### 设置
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
import tensorflow_datasets as tfds
```
### 低阶变量和操作执行
低级API使用的示例包括:
* 使用变量范围来控制重用
* 用`tf.get_variable`创建变量。
* 显式访问集合
* 使用以下方法隐式访问集合:
* `tf.global_variables`
* `tf.losses.get_regularization_loss`
* 使用`tf.placeholder`设置图输入
* 用`session.run`执行图形
* 手动初始化变量
#### 转换前
以下是使用TensorFlow 1.x在代码中看起来像这些模式的内容:
```python
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", reuse=tf.AUTO_REUSE):
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 W * x + b
out_a = forward(in_a)
out_b = forward(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]})
```
#### 转换后
在转换后的代码中:
* 变量是本地Python对象.
* `forward`函数仍定义计算。
* `sess.run`调用被替换为对'forward`的调用
* 可以添加可选的`tf.function`装饰器以提高性能。
* 正则化是手动计算的,不涉及任何全局集合。
* **没有会话或占位符**
```python
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)
```
```python
out_b = forward([0,1])
regularizer = tf.keras.regularizers.l2(0.04)
reg_loss = regularizer(W)
```
### 基于`tf.layers`的模型
`tf.layers`模块用于包含依赖于`tf.variable_scope`来定义和重用变量的层函数。
#### 转换前
```python
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)
```
#### 转换后
* 简单的层堆栈可以整齐地放入 `tf.keras.Sequential` 中。 (对于更复杂的模型,请参见 *自定义层和模型* ,以及 *函数式API* 两个教程)
* 模型跟踪变量和正则化损失
* 转换是一对一的,因为有一个从`tf.layers`到`tf.keras.layers`的直接映射。
大多数参数保持不变,但注意区别:
* 训练参数在运行时由模型传递给每个层
* 原来模型函数的第一个参数(input `x` )消失,这是因为层将构建模型与调用模型分开了。
同时也要注意:
* 如果你使用来自`tf.contrib`的初始化器的正则化器,它们的参数变化比其他变量更多。
* 代码不在写入集合,因此像 `tf.losses.get_regularization_loss` 这样的函数将不再返回这些值,这可能会破坏您的训练循环。
```python
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, 3, activation='relu',
kernel_regularizer=tf.keras.regularizers.l2(0.04),
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')
])
train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 1))
```
```python
train_out = model(train_data, training=True)
print(train_out)
```
```python
test_out = model(test_data, training=False)
print(test_out)
```
```python
# 以下是所有可训练的变量。
len(model.trainable_variables)
```
```python
# 这是正规化损失。
model.losses
```
### 混合变量和tf.layers
现存的代码通常将较低级别的TF 1.x变量和操作与较高级的 `tf.layers` 混合。
#### 转换前
```python
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)
```
#### 转换后
要转换此代码,请遵循将图层映射到图层的模式,如上例所示。
一般模式是:
* 在`__init__`中收集图层参数。
* 在`build`中构建变量。
* 在`call`中执行计算,并返回结果。
`tf.variable_scope`实际上是它自己的一层。所以把它重写为`tf.keras.layers.Layer`。
有关信息请参阅 [指南](https://tensorflow.google.cn/beta/guide/keras/custom_layers_and_models)
```python
# Create a custom layer for part of the model
class CustomLayer(tf.keras.layers.Layer):
def __init__(self, *args, **kwargs):
super(CustomLayer, self).__init__(*args, **kwargs)
def build(self, input_shape):
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):
if training:
return inputs + self.w
else:
return inputs + self.w * 0.5
```
```python
custom_layer = CustomLayer()
print(custom_layer([1]).numpy())
print(custom_layer([1], training=True).numpy())
```
```python
train_data = tf.ones(shape=(1, 28, 28, 1))
test_data = tf.ones(shape=(1, 28, 28, 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, training=False)
```
需要注意以下几点:
* 子类化的Keras模型和层需要在v1图(没有自动控制依赖关系)和eager模式下运行
* 将`call()`包装在`tf.function()`中以获取自动图和自动控制依赖关系
* 不要忘了调用时需要一个训练参数( `tf.Tensor` 或Python布尔值)
* 使用`self.add_weight()`在构造函数或`def build()`中创建模型变量
* 在`build`中,您可以访问输入形状,因此可以创建具有匹配形状的权重。
* 使用`tf.keras.layers.Layer.add_weight`允许Keras跟踪变量和正则化损失。
* 不要在对象中保留`tf.Tensors`。
* 它们可能在`tf.function`中或在 eager 的上下文中创建,并且这些张量的行为也不同。
* 使用`tf.Variable`s作为状态,它们总是可用于两种情况
* `tf.Tensors`仅适用于中间值。
### 关于Slim&contrib.layers的说明
大量较旧的TensorFlow 1.x代码使用 [Slim](https://ai.googleblog.com/2016/08/tf-slim-high-level-library-to-define.html) 库,与TensorFlow 1.x一起打包为`tf.contrib.layers`。作为`contrib`模块,TensorFlow 2.0中不再提供此功能,即使在`tf.compat.v1`中也是如此。使用Slim转换为TF 2.0比转换使用`tf.layers`的存储库更复杂。事实上,首先将Slim代码转换为`tf.layers`然后转换为Keras可能是有意义的。
- 删除 `arg_scopes`,所有args都需要显式
- 如果您使用它们,请将 `normalizer_fn `和 `activation_fn` 拆分为它们自己的图层
- 可分离的转换层映射到一个或多个不同的Keras层(深度、点和可分离的Keras层)
- Slim和 `tf.layers` 具有不同的arg名称和默认值
- 有些args有不同的尺度
- 如果您使用Slim预训练模型,请尝试使用 `tf.keras.applications` 或 [TFHub](https://tensorflow.orb/hub)
一些`tf.contrib`图层可能没有被移动到核心TensorFlow,而是被移动到了 [TF附加组件包](https://github.com/tensorflow/addons).
## 训练
有很多方法可以将数据提供给`tf.keras`模型。他们将接受Python生成器和Numpy数组作为输入。
将数据提供给模型的推荐方法是使用`tf.data`包,其中包含一组用于处理数据的高性能类。
如果您仍在使用tf.queue,则仅支持这些作为数据结构,而不是数据管道。
### 使用Datasets
[TensorFlow数据集包](https://tensorflow.org/datasets) (`tfds`) 包含用于将预定义数据集加载为 `tf.data.Dataset` 对象的使用程序。
对于此示例,使用 `tfds` 加载MNIST数据集:
```python
datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)
mnist_train, mnist_test = datasets['train'], datasets['test']
```
然后为训练准备数据:
* 重新缩放每个图像
* 打乱样本数据的顺序
* 收集批量图像和标签
```python
BUFFER_SIZE = 10 # 实际代码中使用更大的值
BATCH_SIZE = 64
NUM_EPOCHS = 5
def scale(image, label):
image = tf.cast(image, tf.float32)
image /= 255
return image, label
```
要使示例保持简短,请修剪数据集以仅返回5个批次:
```python
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
train_data = train_data.take(STEPS_PER_EPOCH)
test_data = test_data.take(STEPS_PER_EPOCH)
```
```
image_batch, label_batch = next(iter(train_data))
```
### 使用Keras训练循环
如果你不需要对训练过程进行低级别的控制,建议使用Keras内置的fit、evaluate和predict方法,这些方法提供了一个统一的接口来训练模型,而不管实现是什么(sequential、functional或子类化的)。
这些方法的有点包括:
- 它们接受Numpy数组、Python生成器和 `tf.data.Datasets`
- 它们自动应用正则化和激活损失
- 它们支持用于多设备训练的 `tf.distribute`
- 它们支持任意的callables作为损失和指标
- 它们支持回调,如 `tf.keras.callbacks.TensorBoard` 和自定义回调
- 它们具有高性能,可自动使用TensorFlow图形
以下是使用数据集训练模型的示例:
```python
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='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(train_data, epochs=NUM_EPOCHS)
loss, acc = model.evaluate(test_data)
print("Loss {}, Accuracy {}".format(loss, acc))
```
### 编写你自己的训练循环
如果Keras模型的训练步骤适合您,但您需要在该步骤之外进行更多的控制,请考虑在您自己的数据迭代循环中使用 `tf.keras.model.train_on_batch` 方法。
记住:许多东西可以作为 `tf.keras.Callback` 的实现。
此方法具有上一节中提到的方法的许多优点,但允许用户控制外循环。
您还可以使用 `tf.keras.model.test_on_batch` 或 `tf.keras.Model.evaluate` 来检查训练期间的性能。
注意:`train_on_batch`和`test_on_batch`,默认返回单批的损失和指标。如果你传递`reset_metrics = False`,它们会返回累积的指标,你必须记住适当地重置指标累加器。还要记住,像 `AUC` 这样的一些指标需要正确计算 `reset_metrics = False`。
继续训练上面的模型:
```python
# 模型是没有自定义图层的完整模型
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
metrics_names = model.metrics_names
for epoch in range(NUM_EPOCHS):
#Reset the metric accumulators
model.reset_metrics()
for image_batch, label_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,
# return accumulated metrics
reset_metrics=False)
print("\neval: ",
"{}: {:.3f}".format(metrics_names[0], result[0]),
"{}: {:.3f}".format(metrics_names[1], result[1]))
```
<p id="custom_loops"/>
### 自定义训练步骤
如果您需要更多的灵活性和控制,可以通过实现自己的训练循环来实现,有三个步骤:
1. 迭代Python生成器或tf.data.Dataset以获取样本数据;
2. 使用tf.GradientTape收集渐变;
3. 使用tf.keras.optimizer将权重更新应用于模型。
记住:
- 始终在子类层和模型的调用方法中包含一个训练参数。
- 确保在正确设置训练参数的情况下调用模型。
- 根据使用情况,在对一批数据运行模型之前,模型变量可能不存在。
- 您需要手动处理模型的正则化损失等事情
请注意相对于v1的简化:
- 不需要运行变量初始化器,变量在创建时初始化。
- 不需要添加手动控制依赖项,即使在tf.function中,操作也像在eager模式下一样。
上面的模型:
```python
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')
])
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)
```
### 新型指标
在TensorFlow 2.0中,metrics是对象,Metrics对象在eager和tf.functions中运行,一个metrics具有以下方法:
* ` update_state()` – 添加新的观察结果
* `result()` – 给定观察值,获取metrics的当前结果
* `reset_states()` – 清除所有观察值
对象本身是可调用的,与 `update_state` 一样,调用新观察更新状态,并返回metrics的新结果。
你不需要手动初始化metrics的变量,而且因为TensorFlow 2.0具有自动控制依赖项,所以您也不需要担心这些。
下面的代码使用metrics来跟踪自定义训练循环中观察到的平均损失:
```python
# 创建metrics
loss_metric = tf.keras.metrics.Mean(name='train_loss')
accuracy_metric = 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_metric.update_state(total_loss)
accuracy_metric.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))
```
## 保存和加载
### Checkpoint兼容性
TensorFlow 2.0使用基于对象的检查点。
如果小心的话,仍然可以加载旧式的基于名称的检查点,代码转换过程可能会导致变量名的更改,但是有一些变通的方法。
最简单的方法是将新模型的名称与检查点的名称对齐:
- 变量仍然都有你可以设置的名称参数。
- Keras模型还采用名称参数,并将其设置为变量的前缀。
- `tf.name_scope` 函数可用于设置变量名称前缀,这与 `tf.variable_scope` 非常不同,它只影响名称,不跟踪变量和重用。
如果这不适合您的用例,请尝试使用 `tf.compat.v1.train.init_from_checkpoint` 函数,它需要一个 `assignment_map` 参数,该参数指定从旧名称到新名称的映射。
注意:与基于对象的检查点(可以[延迟加载](https://tensorflow.google.cn/beta/guide/checkpoints#loading_mechanics)不同,基于名称的检查点要求在调用函数时构建所有变量。某些模型推迟构建变量,直到您调用 `build` 或在一批数据上运行模型。
### 保存的模型兼容性
对于保存的模型没有明显的兼容性问题:
- TensorFlow 1.x saved_models在TensorFlow 2.0中工作。
- 如果支持所有操作,TensorFlow 2.0 saved_models甚至可以在TensorFlow
1.x中加载工作。
## Estimators
### 使用Estimators进行训练
TensorFlow 2.0支持Estimators,使用Estimators时,可以使用TensorFlow
1.x中的 `input_fn()` 、`tf.extimatro.TrainSpec` 和 `tf.estimator.EvalSpec`。
以下是使用 `input_fn` 和train以及evaluate的示例:
#### 创建input_fn和train/eval规范
```python
# 定义一个estimator的input_fn
def input_fn():
datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True)
mnist_train, mnist_test = datasets['train'], datasets['test']
BUFFER_SIZE = 10000
BATCH_SIZE = 64
def scale(image, label):
image = tf.cast(image, tf.float32)
image /= 255
return image, label[..., tf.newaxis]
train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
return train_data.repeat()
# 定义 train & eval specs
train_spec = tf.estimator.TrainSpec(input_fn=input_fn,
max_steps=STEPS_PER_EPOCH * NUM_EPOCHS)
eval_spec = tf.estimator.EvalSpec(input_fn=input_fn,
steps=STEPS_PER_EPOCH)
```
### 使用Keras模型定义
在TensorFlow2.0中如何构建estimators存在一些差异。
我们建议您使用Keras定义模型,然后使用 `tf.keras.model_to_estimator` 将您的模型转换为estimator。下面的代码展示了如何在创建和训练estimator时使用这个功能。
```python
def make_model():
return 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 = make_model()
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
estimator = tf.keras.estimator.model_to_estimator(
keras_model = model
)
tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)
```
### 使用自定义 `model_fn`
如果您需要维护现有的自定义估算器 `model_fn`,则可以将 `model_fn` 转换为使用Keras模型。
但是出于兼容性原因,自定义 `model_fn` 仍将以1.x样式的图形模式运行,这意味着没有eager execution,也没有自动控制依赖。
在自定义 `model_fn` 中使用Keras模型类似于在自定义训练循环中使用它:
- 根据mode参数适当设置训练阶段
- 将模型的 `trainable_variables` 显示传递给优化器
但相对于自定义循环,存在重要差异:
- 使用 `tf.keras.Model.get_losses_for` 提取损失,而不是使用 `model.losses`
- 使用 `tf.keras.Model.get_updates_for` 提取模型的更新
注意:“更新”是每批后需要应用于模型的更改。例如,`tf.keras.layers.BatchNormalization`层中均值和方差的移动平均值。
以下代码从自定义`model_fn`创建一个估算器,说明所有这些问题。
```python
def my_model_fn(features, labels, mode):
model = make_model()
optimizer = tf.compat.v1.train.AdamOptimizer()
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()
training = (mode == tf.estimator.ModeKeys.TRAIN)
predictions = model(features, training=training)
reg_losses = model.get_losses_for(None) + model.get_losses_for(features)
total_loss = loss_fn(labels, predictions) + tf.math.add_n(reg_losses)
accuracy = tf.compat.v1.metrics.accuracy(labels=labels,
predictions=tf.math.argmax(predictions, axis=1),
name='acc_op')
update_ops = model.get_updates_for(None) + model.get_updates_for(features)
minimize_op = optimizer.minimize(
total_loss,
var_list=model.trainable_variables,
global_step=tf.compat.v1.train.get_or_create_global_step())
train_op = tf.group(minimize_op, update_ops)
return tf.estimator.EstimatorSpec(
mode=mode,
predictions=predictions,
loss=total_loss,
train_op=train_op, eval_metric_ops={'accuracy': accuracy})
# Create the Estimator & Train
estimator = tf.estimator.Estimator(model_fn=my_model_fn)
tf.estimator.train_and_evaluate(estimator, train_spec, eval_spec)
```
## TensorShape
这个类被简化为保存`int`s,而不是`tf.compat.v1.Dimension`对象。所以不需要调用`.value()`来获得`int`。
仍然可以从`tf.TensorShape.dims`访问单个`tf.compat.v1.Dimension`对象。
以下演示了TensorFlow 1.x和TensorFlow 2.0之间的区别。
```
# 创建一个shape并选择一个索引
i = 0
shape = tf.TensorShape([16, None, 256])
shape
```
TF 1.x 运行:
```python
value = shape[i].value
```
TF 2.0 运行::
```python
value = shape[i]
value
```
TF 1.x 运行::
```python
for dim in shape:
value = dim.value
print(value)
```
TF 2.0 运行::
```python
for value in shape:
print(value)
```
在TF 1.x(或使用任何其他维度方法)中运行:
```python
dim = shape[i]
dim.assert_is_compatible_with(other_dim)
```
TF 2.0运行:
```python
other_dim = 16
Dimension = tf.compat.v1.Dimension
if shape.rank is None:
dim = Dimension(None)
else:
dim = shape.dims[i]
dim.is_compatible_with(other_dim) # or any other dimension method
```
```python
shape = tf.TensorShape(None)
if shape:
dim = shape.dims[i]
dim.is_compatible_with(other_dim) # or any other dimension method
```
如果等级已知,则 `tf.TensorShape` 的布尔值为“True”,否则为“False”。
```python
print(bool(tf.TensorShape([]))) # 标量 Scalar
print(bool(tf.TensorShape([0]))) # 0长度的向量 vector
print(bool(tf.TensorShape([1]))) # 1长度的向量 vector
print(bool(tf.TensorShape([None]))) # 未知长度的向量
print(bool(tf.TensorShape([1, 10, 100]))) # 3D tensor
print(bool(tf.TensorShape([None, None, None]))) # 3D tensor with no known dimensions
print()
print(bool(tf.TensorShape(None))) # 未知等级的张量
```
## 其他行为改变
您可能会遇到TensorFlow 2.0中的一些其他行为变化。
### ResourceVariables
TensorFlow 2.0默认创建`ResourceVariables`,而不是`RefVariables`。
`ResourceVariables`被锁定用于写入,因此提供更直观的一致性保证。
* 这可能会改变边缘情况下的行为
* 这可能偶尔会创建额外的副本,可能会有更高的内存使用量
* 可以通过将`use_resource = False`传递给`tf.Variable`构造函数来禁用它。
### Control Flow
控制流op实现得到了简化,因此在TensorFlow 2.0中生成了不同的图。
## 结论
回顾一下本节内容:
1. 运行更新脚本
2. 删除contrib符号
3. 将模型切换为面向对象的样式(Keras)
4. 尽可能使用`tf.keras`或`tf.estimator`培训和评估循环。
5. 否则,请使用自定义循环,但请务必避免会话和集合。
将代码转换为TensorFlow 2.0需要一些工作,但会有以下改变:
- 更少的代码行
- 提高清晰度和简洁性
- 调试更简单
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-guide-migration_guide.html](https://www.mashangxue123.com/tensorflow/tf2-guide-migration_guide.html)
> 英文版本:[https://tensorflow.google.cn/beta/guide/migration_guide](https://tensorflow.google.cn/beta/guide/migration_guide)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/migration_guide.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/guide/migration_guide.md)
================================================
FILE: r2/tutorials/eager/automatic_differentiation.md
================================================
---
title: TF梯度下降法的核心自动微分和梯度带
categories: tensorflow2官方教程
tags: tensorflow2.0教程
top: 1953
abbrlink: tensorflow/tf2-tutorials-eager-automatic_differentiation
---
# TF梯度下降法的核心自动微分和梯度带 (tensorflow2.0官方教程翻译)
在上一个教程中,我们介绍了张量及其操作。在本教程中,我们将介绍自动微分,这是优化机器学习模型的关键技术。
> 备注:在此之前,机器学习社区中很少发挥这个利器,一般都是用Backpropagation(反向传播算法)进行梯度求解,然后使用SGD等进行优化更新。手动实现过backprop算法的同学应该可以体会到其中的复杂性和易错性,一个好的框架应该可以很好地将这部分难点隐藏于用户视角,而自动微分技术恰好可以优雅解决这个问题。梯度下降法(Gradient Descendent)是机器学习的核心算法之一,自动微分则是梯度下降法的核心;梯度下降是通过计算参数与损失函数的梯度并在梯度的方向不断迭代求得极值;
## 1. 导入包
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
```
## 2. 梯度带(Gradient tapes)
TensorFlow提供了 [tf.GradientTape](https://www.tensorflow.org/api_docs/python/tf/GradientTape) API 用于自动微分(计算与输入变量相关的计算梯度)。
Tensorflow将在 `tf.GradientTape` 上下文中执行的所有操作“records(记录)”到“tape(磁带)”上。然后,TensorFlow使用该磁带和与每个记录操作相关的梯度,使用反向模式微分“记录”计算的梯度。例如:
```python
x = tf.ones((2, 2))
with tf.GradientTape() as t:
t.watch(x)
y = tf.reduce_sum(x)
z = tf.multiply(y, y)
# Derivative of z with respect to the original input tensor x
dz_dx = t.gradient(z, x)
for i in [0, 1]:
for j in [0, 1]:
assert dz_dx[i][j].numpy() == 8.0
```
您还可以根据在“记录的”tf.GradientTape上下文中计算的中间值请求输出的梯度。
```python
x = tf.ones((2, 2))
with tf.GradientTape() as t:
t.watch(x)
y = tf.reduce_sum(x)
z = tf.multiply(y, y)
# Use the tape to compute the derivative of z with respect to the
# intermediate value y.
dz_dy = t.gradient(z, y)
assert dz_dy.numpy() == 8.0
```
默认情况下,GradientTape持有的资源会在调用 `GradientTape.gradient()` 方法后立即释放。要在同一计算中计算多个梯度,请创建一个持久梯度带,这允许多次调用 `gradient()` 方法,当磁带对象被垃圾收集时释放资源。例如:
```python
x = tf.constant(3.0)
with tf.GradientTape(persistent=True) as t:
t.watch(x)
y = x * x
z = y * y
dz_dx = t.gradient(z, x) # 108.0 (4*x^3 at x = 3)
dy_dx = t.gradient(y, x) # 6.0
del t # Drop the reference to the tape
```
### 2.1. 记录控制流程
因为tapes(磁带)在执行时记录操作,所以Python控制流程(例如使用 `if` 和 `while`)自然会被处理:
```python
def f(x, y):
output = 1.0
for i in range(y):
if i > 1 and i < 5:
output = tf.multiply(output, x)
return output
def grad(x, y):
with tf.GradientTape() as t:
t.watch(x)
out = f(x, y)
return t.gradient(out, x)
x = tf.convert_to_tensor(2.0)
assert grad(x, 6).numpy() == 12.0
assert grad(x, 5).numpy() == 12.0
assert grad(x, 4).numpy() == 4.0
```
### 2.2. 高阶梯度
`GradientTape` 上下文管理器内的操作将被记录下来,以便自动微分。如果在该上下文中计算梯度,那么梯度计算也会被记录下来。因此,同样的API也适用于高阶梯度。例如:
```python
x = tf.Variable(1.0) # Create a Tensorflow variable initialized to 1.0
with tf.GradientTape() as t:
with tf.GradientTape() as t2:
y = x * x * x
# Compute the gradient inside the 't' context manager
# which means the gradient computation is differentiable as well.
dy_dx = t2.gradient(y, x)
d2y_dx2 = t.gradient(dy_dx, x)
assert dy_dx.numpy() == 3.0
assert d2y_dx2.numpy() == 6.0
```
## 3. 下一步
在本教程中,我们介绍了TensorFlow中的梯度计算。有了这个,我们就拥有了构建和训练神经网络所需的足够原语。
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-automatic_differentiation.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-automatic_differentiation.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/automatic_differentiation](https://tensorflow.google.cn/beta/tutorials/eager/automatic_differentiation)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/automatic_differentiation.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/automatic_differentiation.md)
================================================
FILE: r2/tutorials/eager/basics.md
================================================
---
title: tensorflow2.0张量及其操作、numpy兼容、GPU加速
categories: tensorflow2官方教程
tags: tensorflow2.0教程
top: 1951
abbrlink: tensorflow/tf2-tutorials-eager-basics
---
# tensorflow2.0张量及其操作、numpy兼容、GPU加速 (tensorflow2.0官方教程翻译)
这是一个基础入门的TensorFlow教程,展示了如何:
* 导入所需的包
* 创建和使用张量
* 使用GPU加速
* 演示 `tf.data.Dataset`
```python
from __future__ import absolute_import, division, print_function
```
## 1. 导入TensorFlow
要开始,请导入tensorflow模块。从TensorFlow 2.0开始,默认情况下用会启用Eager execution,这使得TensorFlow能够实现更加互动的前端,我们将在稍后讨论这些细节。
```python
import tensorflow as tf
```
## 2. 张量
张量是一个多维数组,与NumPy的 `ndarray` 对象类似,`tf.Tensor` 对象具有数据类型和形状,此外,`tf.Tensor` 可以驻留在加速器内存中(如GPU)。TensorFlow提供了丰富的操作库(([tf.add](https://www.tensorflow.org/api_docs/python/tf/add), [tf.matmul](https://www.tensorflow.org/api_docs/python/tf/matmul), [tf.linalg.inv](https://www.tensorflow.org/api_docs/python/tf/linalg/inv) 等),它们使用和生成`tf.Tensor`。这些操作会自动转换本机Python类型,例如:
```python
print(tf.add(1, 2))
print(tf.add([1, 2], [3, 4]))
print(tf.square(5))
print(tf.reduce_sum([1, 2, 3]))
# 操作符重载也支持
print(tf.square(2) + tf.square(3))
```
```
tf.Tensor(3, shape=(), dtype=int32)
tf.Tensor([4 6], shape=(2,), dtype=int32)
tf.Tensor(25, shape=(), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(13, shape=(), dtype=int32)
```
每个 `tf.Tensor` 有一个形状和数据类型:
```python
x = tf.matmul([[1]], [[2, 3]])
print(x)
print(x.shape)
print(x.dtype)
```
```
tf.Tensor([[2 3]], shape=(1, 2), dtype=int32) (1, 2) <dtype: 'int32'>
```
NumPy数组和 `tf.Tensor` 之间最明显的区别是:
1. 张量可以有加速器内存(如GPU,TPU)支持。
2. 张量是不可改变的。
### 2.1 NumPy兼容性
在TensorFlow的 `tf.Tensor` 和NumPy的 `ndarray` 之间转换很容易:
* TensorFlow操作自动将NumPy ndarray转换为Tensor
* NumPy操作自动将Tensor转换为NumPy ndarray
使用`.numpy()`方法将张量显式转换为NumPy `ndarrays`。这些转换通常很便宜,因为如果可能的话,数组和`tf.Tensor`共享底层的内存表示。但是,共享底层表示并不总是可行的,因为`tf.Tensor`可以托管在GPU内存中,而NumPy阵列总是由主机内存支持,并且转换涉及从GPU到主机内存的复制。
```python
import numpy as np
ndarray = np.ones([3, 3])
print("TensorFlow operations convert numpy arrays to Tensors automatically")
tensor = tf.multiply(ndarray, 42)
print(tensor)
print("And NumPy operations convert Tensors to numpy arrays automatically")
print(np.add(tensor, 1))
print("The .numpy() method explicitly converts a Tensor to a numpy array")
print(tensor.numpy())
```
```
TensorFlow operations convert numpy arrays to Tensors automatically
tf.Tensor( [[42. 42. 42.] [42. 42. 42.] [42. 42. 42.]], shape=(3, 3), dtype=float64)
And NumPy operations convert Tensors to numpy arrays automatically
[[43. 43. 43.] [43. 43. 43.] [43. 43. 43.]]
The .numpy() method explicitly converts a Tensor to a numpy array
[[42. 42. 42.] [42. 42. 42.] [42. 42. 42.]]
```
## 3. GPU加速
使用GPU进行计算可以加速许多TensorFlow操作,如果没有任何注释,TensorFlow会自动决定是使用GPU还是CPU进行操作,如果有必要,可以复制CPU和GPU内存之间的张量,操作产生的张量通常由执行操作的设备的存储器支持,例如:
```python
x = tf.random.uniform([3, 3])
print("Is there a GPU available: "),
print(tf.test.is_gpu_available())
print("Is the Tensor on GPU #0: "),
print(x.device.endswith('GPU:0'))
```
### 3.1 设备名称
`Tensor.device`属性提供托管张量内容的设备的完全限定字符串名称。此名称编码许多详细信息,例如正在执行此程序的主机的网络地址的标识符以及该主机中的设备。这是分布式执行TensorFlow程序所必需的。如果张量位于主机上的第N个GPU上,则字符串以 `GPU:<N>` 结尾。
### 3.2 显式设备放置
在TensorFlow中,*placement* (放置)指的是如何分配(放置)设备以执行各个操作,如上所述,如果没有提供明确的指导,TensorFlow会自动决定执行操作的设备,并在需要时将张量复制到该设备。但是,可以使用 `tf.device` 上下文管理器将TensorFlow操作显式放置在特定设备上,例如:
```python
import time
def time_matmul(x):
start = time.time()
for loop in range(10):
tf.matmul(x, x)
result = time.time()-start
print("10 loops: {:0.2f}ms".format(1000*result))
# Force execution on CPU
print("On CPU:")
with tf.device("CPU:0"):
x = tf.random.uniform([1000, 1000])
assert x.device.endswith("CPU:0")
time_matmul(x)
# Force execution on GPU #0 if available
if tf.test.is_gpu_available():
print("On GPU:")
with tf.device("GPU:0"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.
x = tf.random.uniform([1000, 1000])
assert x.device.endswith("GPU:0")
time_matmul(x)
```
```
On CPU: 10 loops: 88.60ms
```
## 4. 数据集
本节使用 [`tf.data.Dataset` API](https://www.tensorflow.org/guide/datasets) 构建管道,以便为模型提供数据。 `tf.data.Dataset` API用于从简单,可重复使用的部分构建高性能,复杂的输入管道,这些部分将为模型的训练或评估循环提供支持。
### 4.1 创建源数据集
使用其中一个工厂函数(如 [`Dataset.from_tensors`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#from_tensors), [`Dataset.from_tensor_slices`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#from_tensor_slices))或使用从[`TextLineDataset`](https://www.tensorflow.org/api_docs/python/tf/data/TextLineDataset) 或 [`TFRecordDataset`](https://www.tensorflow.org/api_docs/python/tf/data/TFRecordDataset) 等文件读取的对象创建源数据集。有关详细信息,请参阅[TensorFlow数据集指南](https://www.tensorflow.org/guide/datasets#reading_input_data)。
```python
ds_tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])
# Create a CSV file
import tempfile
_, filename = tempfile.mkstemp()
with open(filename, 'w') as f:
f.write("""Line 1
Line 2
Line 3
""")
ds_file = tf.data.TextLineDataset(filename)
```
### 4.2 应用转换
使用 [`map`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#map), [`batch`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#batch), 和 [`shuffle`](https://www.tensorflow.org/api_docs/python/tf/data/Dataset#shuffle)等转换函数将转换应用于数据集记录。
```python
ds_tensors = ds_tensors.map(tf.square).shuffle(2).batch(2)
ds_file = ds_file.batch(2)
```
### 4.3 迭代(Iterate)
`tf.data.Dataset` 对象支持迭代循环:
```python
print('Elements of ds_tensors:')
for x in ds_tensors:
print(x)
print('\nElements in ds_file:')
for x in ds_file:
print(x)
```
```
Elements of ds_tensors:
tf.Tensor([1 9], shape=(2,), dtype=int32)
tf.Tensor([ 4 25], shape=(2,), dtype=int32)
tf.Tensor([16 36], shape=(2,), dtype=int32)
Elements in ds_file:
tf.Tensor([b'Line 1' b'Line 2'], shape=(2,), dtype=string)
tf.Tensor([b'Line 3' b' '], shape=(2,), dtype=string)
```
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-basics.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-basics.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/basics](https://tensorflow.google.cn/beta/tutorials/eager/basics)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/basics.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/basics.md)
================================================
FILE: r2/tutorials/eager/custom_layers.md
================================================
---
title: 使用Keras自定义层
categories: tensorflow2官方教程
tags: tensorflow2.0教程
top: 1952
abbrlink: tensorflow/tf2-tutorials-eager-custom_layers
---
# 使用Keras自定义层 (tensorflow2.0官方教程翻译)
我们建议使用 `tf.keras` 作为构建神经网络的高级API,也就是说,大多数TensorFlow API都可用于Eager execution。
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
```
## 1. 对图层的常用操作
在编写机器学习模型的代码时,大多数情况下,您希望以比单个操作和单个变量操作更高的抽象级别上进行操作。
许多机器学习模型都可以表示为相对简单的层的组合和叠加,TensorFlow提供了一组公共层和一种简单的方法,让您可以从头开始编写自己的特定于应用程序的层,也可以表示为现有层的组合。
TensorFlow在 `tf.keras` 中包含完整 [Keras](https://keras.io) API,而Keras层在构建自己的模型时非常有用。
```python
# 在tf.keras.layers包中,图层是对象。要构造一个图层,只需构造一个对象。
# 大多数层将输出维度/通道的数量作为第一个参数。
layer = tf.keras.layers.Dense(100)
# 输入维度的数量通常是不必要的,因为它可以在第一次使用层时推断出来,
# 但如果您想手动指定它,则可以提供它,这在某些复杂模型中很有用。
layer = tf.keras.layers.Dense(10, input_shape=(None, 5))
```
可以在文档([链接](https://www.tensorflow.org/api_docs/python/tf/keras/layers))中看到预先存在的层的完整列表,它包括Dense(完全连接层),Conv2D,LSTM,BatchNormalization,Dropout等等。
```python
# 要使用图层,只需调用它即可。
layer(tf.zeros([10, 5]))
```
```python
# 层有许多有用的方法,例如,您可以使用 `layer.variables` 和可训练变量使用
# `layer.trainable_variables`检查图层中的所有变量,在这种情况下,
# 完全连接的层将具有权重和偏差的变量。
print(layer.variables)
```
```python
# 变量也可以通过nice accessors访问
print(layer.kernel, layer.bias)
```
## 2. 使用keras实现自定义层
实现自己的层的最佳方法是扩展`tf.keras.Layer` 类并实现:
* `__init__` ,您可以在其中执行所有与输入无关的初始化
* `build`,您可以在其中了解输入张量的形状,并可以执行其余的初始化
* `call`,在那里进行正向计算。
请注意,您不必等到调用 `build` 来创建变量,您也可以在 `__init__`中创建它们。但是,在 `build` 中创建它们的好处是,它支持根据将要操作的层的输入形状,创建后期变量。另一方面,在 `__init__` 中创建变量意味着需要明确指定创建变量所需的形状。
```python
class MyDenseLayer(tf.keras.layers.Layer):
def __init__(self, num_outputs):
super(MyDenseLayer, self).__init__()
self.num_outputs = num_outputs
def build(self, input_shape):
self.kernel = self.add_variable("kernel",
shape=[int(input_shape[-1]),
self.num_outputs])
def call(self, input):
return tf.matmul(input, self.kernel)
layer = MyDenseLayer(10)
print(layer(tf.zeros([10, 5])))
print(layer.trainable_variables)
```
如果尽可能使用标准层,则整体代码更易于阅读和维护,因为其他读者将熟悉标准层的行为。如果你想使用 `tf.keras.layers` 中不存在的图层,请考虑提交[github问题](http://github.com/tensorflow/tensorflow/issues/new),或者最好向我们发送pull request!
## 3. 通过组合层构建模型
在机器学习模型中,许多有趣的类似层的事物都是通过组合现有层来实现的。例如,resnet中的每个残差块都是convolutions、 batch normalizations和shortcut的组合。
创建包含其他层的类似层的事物时使用的主类是 `tf.keras.Model`,实现一个是通过继承自 `tf.keras.Model` 完成的。
```python
class ResnetIdentityBlock(tf.keras.Model):
def __init__(self, kernel_size, filters):
super(ResnetIdentityBlock, self).__init__(name='')
filters1, filters2, filters3 = filters
self.conv2a = tf.keras.layers.Conv2D(filters1, (1, 1))
self.bn2a = tf.keras.layers.BatchNormalization()
self.conv2b = tf.keras.layers.Conv2D(filters2, kernel_size, padding='same')
self.bn2b = tf.keras.layers.BatchNormalization()
self.conv2c = tf.keras.layers.Conv2D(filters3, (1, 1))
self.bn2c = tf.keras.layers.BatchNormalization()
def call(self, input_tensor, training=False):
x = self.conv2a(input_tensor)
x = self.bn2a(x, training=training)
x = tf.nn.relu(x)
x = self.conv2b(x)
x = self.bn2b(x, training=training)
x = tf.nn.relu(x)
x = self.conv2c(x)
x = self.bn2c(x, training=training)
x += input_tensor
return tf.nn.relu(x)
block = ResnetIdentityBlock(1, [1, 2, 3])
print(block(tf.zeros([1, 2, 3, 3])))
print([x.name for x in block.trainable_variables])
```
```
tf.Tensor( [[[[0. 0. 0.] [0. 0. 0.] [0. 0. 0.]] [[0. 0. 0.] [0. 0. 0.] [0. 0. 0.]]]], shape=(1, 2, 3, 3), dtype=float32)
['resnet_identity_block/conv2d/kernel:0', 'resnet_identity_block/conv2d/bias:0',
'resnet_identity_block/batch_normalization_v2/gamma:0', 'resnet_identity_block/batch_normalization_v2/beta:0',
'resnet_identity_block/conv2d_1/kernel:0', 'resnet_identity_block/conv2d_1/bias:0',
'resnet_identity_block/batch_normalization_v2_1/gamma:0', 'resnet_identity_block/batch_normalization_v2_1/beta:0',
'resnet_identity_block/conv2d_2/kernel:0', 'resnet_identity_block/conv2d_2/bias:0',
'resnet_identity_block/batch_normalization_v2_2/gamma:0', 'resnet_identity_block/batch_normalization_v2_2/beta:0']
```
然而,在大多数情况下,组成许多层的模型只是简单地调用一个又一个层。这可以通过使用 `tf.keras.Sequential`在很少的代码中完成
```python
my_seq = tf.keras.Sequential([tf.keras.layers.Conv2D(1, (1, 1),
input_shape=(
None, None, 3)),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Conv2D(2, 1,
padding='same'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Conv2D(3, (1, 1)),
tf.keras.layers.BatchNormalization()])
my_seq(tf.zeros([1, 2, 3, 3]))
```
# 4. 下一步
现在,您可以返回到之前的教程,并调整线性回归示例,以使用更好的结构化层和模型。
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_layers.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_layers.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/custom_layers](https://tensorflow.google.cn/beta/tutorials/eager/custom_layers)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_layers.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_layers.md)
================================================
FILE: r2/tutorials/eager/custom_training.md
================================================
---
title: 构建tensorflow2.0模型自定义训练的基础步骤
categories: tensorflow2官方教程
tags: tensorflow2.0教程
top: 1954
abbrlink: tensorflow/tf2-tutorials-eager-custom_training
---
# 构建tensorflow2.0模型自定义训练的基础步骤 (tensorflow2.0官方教程翻译)
在上一个教程中,我们介绍了用于自动微分的TensorFlow API,这是机器学习的基本构建块。在本教程中,我们将使用先前教程中介绍的TensorFlow原语来进行一些简单的机器学习。
TensorFlow还包括一个更高级别的神经网络API(`tf.keras`) ,它提供了有用的抽象来减少引用。我们强烈建议使用神经网络的人使用更高级别的API。
但是,在这个简短的教程中,我们从基本原理入手开始介绍神经网络训练,以建立坚实的基础。
## 1. 设置
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
```
## 2. 变量
TensorFlow中的张量是不可变的无状态对象。然而,机器学习模型需要具有变化的状态:随着模型训练,计算预测的相同代码应该随着时间的推移而表现不同(希望具有较低的损失)。要表示需要在计算过程中进行更改的状态,您可以选择依赖Python是有状态编程语言的这一事实:
```python
# Using python state
x = tf.zeros([10, 10])
x += 2 # This is equivalent to x = x + 2, which does not mutate the original
# value of x
print(x)
```
但是,TensorFlow内置了有状态操作,这些操作通常比您所在状态的低级Python表示更令人愉快。例如,为了表示模型中的权重,使用TensorFlow变量通常是方便有效的。
变量是一个存储值的对象,当在TensorFlow计算中使用时,它将隐式地从该存储值中读取。有一些操作(`tf.assign_sub`, `tf.scatter_update`等)可以操作存储在TensorFlow变量中的值。
```python
v = tf.Variable(1.0)
assert v.numpy() == 1.0
# Re-assign the value
v.assign(3.0)
assert v.numpy() == 3.0
# Use `v` in a TensorFlow operation like tf.square() and reassign
v.assign(tf.square(v))
assert v.numpy() == 9.0
```
计算梯度时会自动跟踪使用变量的计算。对于表示嵌入的变量,TensorFlow默认会进行稀疏更新,这样可以提高计算效率和内存效率。
使用变量也是一种快速让代码的读者知道这段状态是可变的方法。
## 3. 示例:拟合一个线性模型
现在让我们把我们迄今为止的几个概念:`Tensor`, `GradientTape`, `Variable`。构建并训练一个简单的模型。这通常涉及几个步骤:
1. 定义模型
2. 定义损失函数
3. 获取训练数据
4. 运行训练数据并使用“优化器”调整变量以拟合数据。
在本教程中,我们将介绍简单线性模型的一个简单示例: `f(x) = x * W + b`,它有两个变量,`W` 和 `b`。此外,我们将合成数据,使训练有素的模型具有`W = 3.0` 和` b =2.0` 。
### 3.1. 定义模型
让我们定义一个简单的类来封装变量和计算
```python
class Model(object):
def __init__(self):
# Initialize variable to (5.0, 0.0)
# In practice, these should be initialized to random values.
self.W = tf.Variable(5.0)
self.b = tf.Variable(0.0)
def __call__(self, x):
return self.W * x + self.b
model = Model()
assert model(3.0).numpy() == 15.0
```
### 3.2. 定义损失函数
损失函数测量给定输入的模型输出与期望输出的匹配程度。让我们使用标准的L2损失:
```python
def loss(predicted_y, desired_y):
return tf.reduce_mean(tf.square(predicted_y - desired_y))
```
### 3.3. 获取训练数据
让我们用一些噪音合成训练数据:
```python
TRUE_W = 3.0
TRUE_b = 2.0
NUM_EXAMPLES = 1000
inputs = tf.random.normal(shape=[NUM_EXAMPLES])
noise = tf.random.normal(shape=[NUM_EXAMPLES])
outputs = inputs * TRUE_W + TRUE_b + noise
```
在我们训练模型之前,让我们可以看到模型现在所处的位置。我们将用红色绘制模型的预测,用蓝色绘制训练数据。
```python
import matplotlib.pyplot as plt
plt.scatter(inputs, outputs, c='b')
plt.scatter(inputs, model(inputs), c='r')
plt.show()
print('Current loss: '),
print(loss(model(inputs), outputs).numpy())
```
### 3.4. 定义训练循环
我们现在拥有我们的网络和训练数据。让我们训练它,即使用训练数据来更新模型的变量(`W` 和 `b`),以便使用梯度下降来减少损失。在`tf.train.Optimizer`实现中拥有许多梯度下降方案的变体。我们强烈建议使用这些实现,但本着从基本原理构建的精神,在这个特定的例子中,我们将自己实现基本的数学。
```python
def train(model, inputs, outputs, learning_rate):
with tf.GradientTape() as t:
current_loss = loss(model(inputs), outputs)
dW, db = t.gradient(current_loss, [model.W, model.b])
model.W.assign_sub(learning_rate * dW)
model.b.assign_sub(learning_rate * db)
```
最后,让我们反复浏览训练数据,看看W和b是如何演变的。
```python
model = Model()
# Collect the history of W-values and b-values to plot later
Ws, bs = [], []
epochs = range(10)
for epoch in epochs:
Ws.append(model.W.numpy())
bs.append(model.b.numpy())
current_loss = loss(model(inputs), outputs)
train(model, inputs, outputs, learning_rate=0.1)
print('Epoch %2d: W=%1.2f b=%1.2f, loss=%2.5f' %
(epoch, Ws[-1], bs[-1], current_loss))
# Let's plot it all
plt.plot(epochs, Ws, 'r',
epochs, bs, 'b')
plt.plot([TRUE_W] * len(epochs), 'r--',
[TRUE_b] * len(epochs), 'b--')
plt.legend(['W', 'b', 'true W', 'true_b'])
plt.show()
```
```
Epoch 0: W=5.00 b=0.00, loss=9.34552
...
Epoch 9: W=3.22 b=1.74, loss=1.14022
```

## 4. 下一步
在本教程中,我们介绍了变量,并使用到目前为止讨论的TensorFlow原语构建并训练了一个简单的线性模型。
从理论上讲,这几乎是您使用TensorFlow进行机器学习研究所需要的全部内容。在实践中,特别是对于神经网络,像 `tf.keras` 这样的高级API将更加方便,因为它提供了更高级别的构建块(称为“层”),用于保存和恢复状态的实用程序,一套损失函数,套件优化策略等。
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training.htnl)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/custom_training](https://tensorflow.google.cn/beta/tutorials/eager/custom_training)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training.md)
================================================
FILE: r2/tutorials/eager/custom_training_walkthrough.md
================================================
---
title: 使用Keras演示TensorFlow2.0自定义训练实战
tags:
- tensorflow2.0
categories:
- tensorflow2官方教程
top: 1955
abbrlink: tensorflow/tf2-tutorials-eager-custom_training_walkthrough
---
# 使用Keras演示TensorFlow2.0自定义训练实战 (tensorflow2.0官方教程翻译)
本指南使用机器学习对鸢尾花按品种进行分类。它利用 TensorFlow 的 Eager Execution 来执行以下操作:
1. 构建模型
2. 使用样本数据训练该模型
3. 利用该模型对未知数据进行预测。
## 1. TensorFlow 编程
本指南采用了以下高级 TensorFlow 概念:
* 使用TensorFlow的默认 [eager execution](https://www.tensorflow.org/guide/eager) 开发环境,
* 使用 [Datasets API](https://www.tensorflow.org/guide/datasets) 导入数据,
* 使用 TensorFlow 的 [Keras API](https://keras.io/getting-started/sequential-model-guide/) 构建模型和层。
本教程采用了与许多 TensorFlow 程序相似的结构:
1. 导入和解析数据集。
2. 选择模型类型。
3. 训练模型。
4. 评估模型的效果。
5. 使用经过训练的模型进行预测。
## 2. 设置程序
### 2.1. 配置导入
导入所需的 Python 模块(包括 TensorFlow),默认情况下,TensorFlow使用 Eager Execution 来立即评估操作,并返回具体的值,而不是创建稍后执行的计算图。如果您习惯使用 REPL 或 python 交互控制台,对于 Eager Execution 您会用起来得心应手。
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import os
import matplotlib.pyplot as plt
import tensorflow as tf
print("TensorFlow version: {}".format(tf.__version__))
print("Eager execution: {}".format(tf.executing_eagerly()))
```
```
TensorFlow version: 2.0.0-alpha0 Eager execution: True
```
## 3. 鸢尾花分类问题
想象一下,您是一名植物学家,正在寻找一种能够对所发现的每株鸢尾花进行自动归类的方法。机器学习可提供多种从统计学上分类花卉的算法。例如,一个复杂的机器学习程序可以根据照片对花卉进行分类。我们的要求并不高,我们将根据鸢尾花花萼和花瓣的长度和宽度对其进行分类。
鸢尾属约有 300 个品种,但我们的程序将仅对下列三个品种进行分类:
* 山鸢尾
* 维吉尼亚鸢尾
* 变色鸢尾
<table>
<tr><td>
<img src="https://tensorflow.google.cn/images/iris_three_species.jpg"
alt="Petal geometry compared for three iris species: Iris setosa, Iris virginica, and Iris versicolor">
</td></tr>
<tr><td align="center">
<b>图1.</b> <a href="https://commons.wikimedia.org/w/index.php?curid=170298">山鸢尾Iris setosa, <a href="https://commons.wikimedia.org/w/index.php?curid=248095">变色鸢尾Iris versicolor</a>,和 <a href="https://www.flickr.com/photos/33397993@N05/3352169862">维吉尼亚鸢尾Iris virginica</a> <br/>
</td></tr>
</table>
幸运的是,有人已经创建了一个包含 120 株鸢尾花的数据集(其中有花萼和花瓣的测量值)。这是一个在入门级机器学习分类问题中经常使用的经典数据集。
## 4. 导入和解析训练数据集
下载数据集文件并将其转换为可供此 Python 程序使用的结构。
### 4.1. 下载数据集
使用 [tf.keras.utils.get_file](https://www.tensorflow.org/api_docs/python/tf/keras/utils/get_file) 函数下载训练数据集文件。该函数会返回下载文件的文件路径。
```python
train_dataset_url = "https://storage.googleapis.com/download.tensorflow.org/data/iris_training.csv"
train_dataset_fp = tf.keras.utils.get_file(fname=os.path.basename(train_dataset_url),
origin=train_dataset_url)
print("Local copy of the dataset file: {}".format(train_dataset_fp))
```
### 4.2. 检查数据
数据集 `iris_training.csv` 是一个纯文本文件,其中存储了逗号分隔值 (CSV) 格式的表格式数据。请使用 `head -n5` 命令查看前 5 个条目:
```
!head -n5 {train_dataset_fp}
```
```
120,4,setosa,versicolor,virginica
6.4,2.8,5.6,2.2,2
5.0,2.3,3.3,1.0,1
4.9,2.5,4.5,1.7,2
4.9,3.1,1.5,0.1,0
```
我们可以从该数据集视图中注意到以下信息:
1. 第一行是标题,其中包含数据集信息:
* 共有 120 个样本。每个样本都有四个特征和一个标签名称,标签名称有三种可能。
2. 后面的行是数据记录,每个样本各占一行,其中:
* 前四个字段是特征:即样本的特点。在此数据集中,这些字段存储的是代表花卉测量值的浮点数。
* 最后一列是标签:即我们想要预测的值。对于此数据集,该值为 0、1 或 2 中的某个整数值(每个值分别对应一个花卉名称)。
我们用代码表示出来:
```python
# column order in CSV file
column_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species']
feature_names = column_names[:-1]
label_name = column_names[-1]
print("Features: {}".format(feature_names))
print("Label: {}".format(label_name))
```
```
Features: ['sepal_length', 'sepal_width', 'petal_length', 'petal_width'] Label: species
```
每个标签都分别与一个字符串名称(例如“setosa”)相关联,但机器学习通常依赖于数字值。标签编号会映射到一个指定的表示法,例如:
* `0`: 山鸢尾
* `1`: 变色鸢尾
* `2`: 维吉尼亚鸢尾
如需详细了解特征和标签,请参阅[《机器学习速成课程》的“机器学习术语”部分](https://developers.google.cn/machine-learning/crash-course/framing/ml-terminology)。
```python
class_names = ['Iris setosa', 'Iris versicolor', 'Iris virginica']
```
### 4.3. 创建一个 `tf.data.Dataset`
TensorFlow 的 Dataset API 可处理在向模型加载数据时遇到的许多常见情况。这是一种高阶 API,用于读取数据并将其转换为可供训练使用的格式。如需了解详情,请参阅[数据集快速入门指南](https://tensorflow.google.cn/guide/datasets_for_estimators)。
由于数据集是 CSV 格式的文本文件,请使用 make_csv_dataset 函数将数据解析为合适的格式。由于此函数为训练模型生成数据,默认行为是对数据进行随机处理 (`shuffle=True, shuffle_buffer_size=10000`),并且无限期重复数据集 (`num_epochs=None`)。我们还设置了 batch_size 参数。
```python
batch_size = 32
train_dataset = tf.data.experimental.make_csv_dataset(
train_dataset_fp,
batch_size,
column_names=column_names,
label_name=label_name,
num_epochs=1)
```
`make_csv_dataset` 函数返回 `(features, label)` 对的 `tf.data.Dataset`,其中 `features` 是一个字典:`{'feature_name': value}`
这些 Dataset 对象便可迭代。我们来看看一批特征:
```python
features, labels = next(iter(train_dataset))
print(features)
```
请注意,类似特征会归为一组,即分为一批。每个样本行的字段都会附加到相应的特征数组中。更改 batch_size 可设置存储在这些特征数组中的样本数。
绘制该批次中的几个特征后,就会开始看到一些集群现象:
```python
plt.scatter(features['petal_length'],
features['sepal_length'],
c=labels,
cmap='viridis')
plt.xlabel("Petal length")
plt.ylabel("Sepal length")
plt.show()
```

要简化模型构建步骤,请创建一个函数以将特征字典重新打包为形状为 `(batch_size, num_features)` 的单个数组。
此函数使用 [tf.stack](https://tensorflow.google.cn/api_docs/python/tf/stack) 方法,该方法从张量列表中获取值,并创建指定维度的组合张量。
```python
def pack_features_vector(features, labels):
"""Pack the features into a single array."""
features = tf.stack(list(features.values()), axis=1)
return features, labels
```
然后使用 [tf.data.Dataset.map](https://tensorflow.google.cn/api_docs/python/tf/data/dataset/map) 方法将每个 `(features,label)` 对的 `features` 打包到训练数据集中:
```python
train_dataset = train_dataset.map(pack_features_vector)
```
`Dataset` 的 features 元素现在是形状为 `(batch_size, num_features)` 的数组。我们来看看前几个样本:
```python
features, labels = next(iter(train_dataset))
print(features[:5])
```
```
tf.Tensor(
[[4.9 2.4 3.3 1. ]
...
[6.6 3. 4.4 1.4]], shape=(5, 4), dtype=float32)
```
## 5. 选择模型类型
### 5.1. 为何要使用模型?
模型是指特征与标签之间的关系。对于鸢尾花分类问题,模型定义了花萼和花瓣测量值与预测的鸢尾花品种之间的关系。一些简单的模型可以用几行代数进行描述,但复杂的机器学习模型拥有大量难以汇总的参数。
您能否在不使用机器学习的情况下确定四个特征与鸢尾花品种之间的关系?也就是说,您能否使用传统编程技巧(例如大量条件语句)创建模型?也许能,前提是反复分析该数据集,并最终确定花瓣和花萼测量值与特定品种的关系。对于更复杂的数据集来说,这会变得非常困难,或许根本就做不到。一个好的机器学习方法可为您确定模型。如果您将足够多的代表性样本馈送到正确类型的机器学习模型中,该程序便会为您找出相应的关系。
### 5.2. 选择模型
我们需要选择要进行训练的模型类型。模型具有许多类型,挑选合适的类型需要一定的经验。本教程使用神经网络来解决鸢尾花分类问题。神经网络可以发现特征与标签之间的复杂关系。神经网络是一个高度结构化的图,其中包含一个或多个隐藏层。每个隐藏层都包含一个或多个神经元。神经网络有多种类别,该程序使用的是密集型神经网络,也称为全连接神经网络:一个层中的神经元将从上一层中的每个神经元获取输入连接。例如,图 2 显示了一个密集型神经网络,其中包含 1 个输入层、2 个隐藏层以及 1 个输出层:
<table>
<tr><td>
<img src="https://tensorflow.google.cn/images/custom_estimators/full_network.png"
alt="A diagram of the network architecture: Inputs, 2 hidden layers, and outputs">
</td></tr>
<tr><td align="center">
<b>图 2.</b> 包含特征、隐藏层和预测的神经网络 <br/>
</td></tr>
</table>
当图 2 中的模型经过训练并馈送未标记的样本时,它会产生 3 个预测结果:相应鸢尾花属于指定品种的可能性。这种预测称为[推理](https://developers.google.cn/machine-learning/crash-course/glossary#inference)。对于该示例,输出预测结果的总和是 1.0。在图 2 中,该预测结果分解如下:山鸢尾为 0.02,变色鸢尾为 0.95,维吉尼亚鸢尾为 0.03。这意味着该模型预测某个无标签鸢尾花样本是变色鸢尾的概率为 95%。
### 5.3. 使用Keras创建模型
TensorFlow `tf.keras` API 是创建模型和层的首选方式。通过该 API,您可以轻松地构建模型并进行实验,而将所有部分连接在一起的复杂工作则由 Keras 处理。
`tf.keras.Sequential` 模型是层的线性堆叠。该模型的构造函数会采用一系列层实例;在本示例中,采用的是 2 个密集层(分别包含 10 个节点)以及 1 个输出层(包含 3 个代表标签预测的节点)。第一个层的 `input_shape` 参数对应该数据集中的特征数量,它是一项必需参数。
```python
model = tf.keras.Sequential([
tf.keras.layers.Dense(10, activation=tf.nn.relu, input_shape=(4,)), # input shape required
tf.keras.layers.Dense(10, activation=tf.nn.relu),
tf.keras.layers.Dense(3)
])
```
[激活函数](https://developers.google.cn/machine-learning/crash-course/glossary#activation_function)可决定层中每个节点的输出形状。这些非线性关系很重要,如果没有它们,模型将等同于单个层。[激活函数有很多](https://tensorflow.google.cn/api_docs/python/tf/keras/activations),但隐藏层通常使用 [ReLU](https://developers.google.cn/machine-learning/crash-course/glossary#ReLU)。
隐藏层和神经元的理想数量取决于问题和数据集。与机器学习的多个方面一样,选择最佳的神经网络形状需要一定的知识水平和实验基础。一般来说,增加隐藏层和神经元的数量通常会产生更强大的模型,而这需要更多数据才能有效地进行训练。
### 5.4. 查看模型
我们快速了解一下此模型如何处理一批特征:
```
predictions = model(features)
predictions[:5]
```
在此示例中,每个样本针对每个类别返回一个[logit](https://developers.google.cn/machine-learning/crash-course/glossary#logits) 。
要将这些对数转换为每个类别的概率,请使用 [softmax](https://developers.google.cn/machine-learning/crash-course/glossary#softmax) 函数:
```python
tf.nn.softmax(predictions[:5])
```
对每个类别执行 `tf.argmax` 运算可得出预测的类别索引。不过,该模型尚未接受训练,因此这些预测并不理想。
```python
print("Prediction: {}".format(tf.argmax(predictions, axis=1)))
print(" Labels: {}".format(labels))
```
## 6. 训练模型
训练是一个机器学习阶段,在此阶段中,模型会逐渐得到优化,也就是说,模型会了解数据集。目标是充分了解训练数据集的结构,以便对未见过的数据进行预测。如果您从训练数据集中获得了过多的信息,预测便会仅适用于模型见过的数据,但是无法泛化。此问题称为[过拟合](https://developers.google.cn/machine-learning/crash-course/glossary#overfitting),好比将答案死记硬背下来,而不去理解问题的解决方式。
鸢尾花分类问题是监督式机器学习的一个示例:模型通过包含标签的样本加以训练。在非监督式机器学习中,样本不包含标签。相反,模型通常会在特征中发现一些规律。
### 6.1. 定义损失和梯度函数
在训练和评估阶段,我们都需要计算模型的损失。这样可以衡量模型的预测结果与预期标签有多大偏差,也就是说,模型的效果有多差。我们希望尽可能减小或优化这个值。
我们的模型会使用 `tf.keras.losses.SparseCategoricalCrossentropy` 函数计算其损失,此函数会接受模型的类别概率预测结果和预期标签,然后返回样本的平均损失。
```python
loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
```
```python
def loss(model, x, y):
y_ = model(x)
return loss_object(y_true=y, y_pred=y_)
l = loss(model, features, labels)
print("Loss test: {}".format(l))
```
使用 [tf.GradientTape](https://tensorflow..google.cn/api_docs/python/tf/GradientTape) 上下计算用于优化模型的[梯度](https://developers.google.cn/machine-learning/crash-course/glossary#gradient)。
```python
def grad(model, inputs, targets):
with tf.GradientTape() as tape:
loss_value = loss(model, inputs, targets)
return loss_value, tape.gradient(loss_value, model.trainable_variables)
```
### 6.2. 创建优化器
*[优化器](https://developers.google.cn/machine-learning/crash-course/glossary#optimizer)* 会将计算出的梯度应用于模型的变量,以最小化 loss 函数。您可以将损失函数想象为一个曲面(见图 3),我们希望通过到处走动找到该曲面的最低点。梯度指向最高速上升的方向,因此我们将沿相反的方向向下移动。我们以迭代方式计算每个批次的损失和梯度,以在训练过程中调整模型。模型会逐渐找到权重和偏差的最佳组合,从而将损失降至最低。损失越低,模型的预测效果就越好。
<table>
<tr><td>
<img src="https://cs231n.github.io/assets/nn3/opt1.gif" width="70%"
alt="Optimization algorithms visualized over time in 3D space.">
</td></tr>
<tr><td align="center">
<b>图 3.</b> 优化算法在三维空间中随时间推移而变化的可视化效果。<br/>(Source: <a href="http://cs231n.github.io/neural-networks-3/">斯坦福大学 CS231n 课程</a>, MIT License, Image credit: <a href="https://twitter.com/alecrad">Alec Radford</a>)
</td></tr>
</table>
TensorFlow 拥有许多可用于训练的[优化算法](https://www.tensorflow.org/api_guides/python/train)。此模型使用的是 [tf.train.GradientDescentOptimizer](https://www.tensorflow.org/api_docs/python/tf/train/GradientDescentOptimizer),它可以实现[随机梯度下降法](https://developers.google.cn/machine-learning/crash-course/glossary#gradient_descent) (SGD)。`learning_rate` 用于设置每次迭代(向下行走)的步长。这是一个超参数,您通常需要调整此参数以获得更好的结果。
我们来设置优化器:
```python
optimizer = tf.keras.optimizers.Adam(learning_rate=0.01)
```
我们将使用它来计算单个优化步骤:
```python
loss_value, grads = grad(model, features, labels)
print("Step: {}, Initial Loss: {}".format(optimizer.iterations.numpy(),
loss_value.numpy()))
optimizer.apply_gradients(zip(grads, model.trainable_variables))
print("Step: {}, Loss: {}".format(optimizer.iterations.numpy(),
loss(model, features, labels).numpy()))
```
```
Step: 0, Initial Loss: 2.3108744621276855
Step: 1, Loss: 1.7618987560272217
```
### 6.3. 训练循环
一切准备就绪后,就可以开始训练模型了!训练循环会将数据集样本馈送到模型中,以帮助模型做出更好的预测。以下代码块可设置这些训练步骤:
1. 迭代每个周期。通过一次数据集即为一个周期。
2. 在一个周期中,遍历训练 Dataset 中的每个样本,并获取样本的特征 (x) 和标签 (y)。
3. 根据样本的特征进行预测,并比较预测结果和标签。衡量预测结果的不准确性,并使用所得的值计算模型的损失和梯度。
4. 使用 optimizer 更新模型的变量。
5. 跟踪一些统计信息以进行可视化。
6. 对每个周期重复执行以上步骤。
num_epochs 变量是遍历数据集集合的次数。与直觉恰恰相反的是,训练模型的时间越长,并不能保证模型就越好。num_epochs 是一个可以调整的超参数。选择正确的次数通常需要一定的经验和实验基础。
```python
## Note: Rerunning this cell uses the same model variables
# keep results for plotting
train_loss_results = []
train_accuracy_results = []
num_epochs = 201
for epoch in range(num_epochs):
epoch_loss_avg = tf.keras.metrics.Mean()
epoch_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
# Training loop - using batches of 32
for x, y in train_dataset:
# Optimize the model
loss_value, grads = grad(model, x, y)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
# Track progress
epoch_loss_avg(loss_value) # add current batch loss
# compare predicted label to actual label
epoch_accuracy(y, model(x))
# end epoch
train_loss_results.append(epoch_loss_avg.result())
train_accuracy_results.append(epoch_accuracy.result())
if epoch % 50 == 0:
print("Epoch {:03d}: Loss: {:.3f}, Accuracy: {:.3%}".format(epoch,
epoch_loss_avg.result(),
epoch_accuracy.result()))
```
```
Epoch 000: Loss: 1.568, Accuracy: 30.000%
...
Epoch 200: Loss: 0.049, Accuracy: 97.500%
```
### 6.4. 可视化损失函数随时间推移而变化的情况
虽然输出模型的训练过程有帮助,但查看这一过程往往更有帮助。TensorBoard 是与 TensorFlow 封装在一起的出色可视化工具,不过我们可以使用 matplotlib 模块创建基本图表。
解读这些图表需要一定的经验,不过您确实希望看到损失下降且准确率上升。
```python
fig, axes = plt.subplots(2, sharex=True, figsize=(12, 8))
fig.suptitle('Training Metrics')
axes[0].set_ylabel("Loss", fontsize=14)
axes[0].plot(train_loss_results)
axes[1].set_ylabel("Accuracy", fontsize=14)
axes[1].set_xlabel("Epoch", fontsize=14)
axes[1].plot(train_accuracy_results)
plt.show()
```

## 7. 评估模型的效果
模型已经过训练,现在我们可以获取一些关于其效果的统计信息了。
评估指的是确定模型做出预测的效果。要确定模型在鸢尾花分类方面的效果,请将一些花萼和花瓣测量值传递给模型,并要求模型预测它们所代表的鸢尾花品种。然后,将模型的预测结果与实际标签进行比较。例如,如果模型对一半输入样本的品种预测正确,则准确率为 0.5。图 4 显示的是一个效果更好一些的模型,该模型做出 5 次预测,其中有 4 次正确,准确率为 80%:
<table cellpadding="8" border="0">
<colgroup>
<col span="4" >
<col span="1" bgcolor="lightblue">
<col span="1" bgcolor="lightgreen">
</colgroup>
<tr bgcolor="lightgray">
<th colspan="4">样本特征</th>
<th colspan="1">标签</th>
<th colspan="1" >模型预测</th>
</tr>
<tr>
<td>5.9</td><td>3.0</td><td>4.3</td><td>1.5</td><td align="center">1</td><td align="center">1</td>
</tr>
<tr>
<td>6.9</td><td>3.1</td><td>5.4</td><td>2.1</td><td align="center">2</td><td align="center">2</td>
</tr>
<tr>
<td>5.1</td><td>3.3</td><td>1.7</td><td>0.5</td><td align="center">0</td><td align="center">0</td>
</tr>
<tr>
<td>6.0</td> <td>3.4</td> <td>4.5</td> <td>1.6</td> <td align="center">1</td><td align="center" bgcolor="red">2</td>
</tr>
<tr>
<td>5.5</td><td>2.5</td><td>4.0</td><td>1.3</td><td align="center">1</td><td align="center">1</td>
</tr>
<tr><td align="center" colspan="6">
<b>图4.</b> 准确率为 80% 的鸢尾花分类器。<br/>
</td></tr>
</table>
### 7.1. 设置测试数据集
评估模型与训练模型相似。最大的区别在于,样本来自一个单独的测试集,而不是训练集。为了公正地评估模型的效果,用于评估模型的样本务必与用于训练模型的样本不同。
测试 Dataset 的设置与训练 Dataset 的设置相似。下载 CSV 文本文件并解析相应的值,然后对数据稍加随机化处理:
```python
test_url = "https://storage.googleapis.com/download.tensorflow.org/data/iris_test.csv"
test_fp = tf.keras.utils.get_file(fname=os.path.basename(test_url),
origin=test_url)
```
```python
test_dataset = tf.data.experimental.make_csv_dataset(
test_fp,
batch_size,
column_names=column_names,
label_name='species',
num_epochs=1,
shuffle=False)
test_dataset = test_dataset.map(pack_features_vector)
```
### 7.2. 根据测试数据集评估模型
与训练阶段不同,模型仅评估测试数据的一个周期。在以下代码单元格中,我们会遍历测试集中的每个样本,然后将模型的预测结果与实际标签进行比较。这是为了衡量模型在整个测试集中的准确率。
```python
test_accuracy = tf.keras.metrics.Accuracy()
for (x, y) in test_dataset:
logits = model(x)
prediction = tf.argmax(logits, axis=1, output_type=tf.int32)
test_accuracy(prediction, y)
print("Test set accuracy: {:.3%}".format(test_accuracy.result()))
```
```
Test set accuracy: 96.667%
```
例如,我们可以看到对于最后一批数据,该模型通常预测正确:
```python
tf.stack([y,prediction],axis=1)
```
```
<tf.Tensor: id=164408, shape=(30, 2), dtype=int32, numpy=
array([[1, 1],
[2, 2],
[0, 0],..., dtype=int32)>
```
## 8. 使用经过训练的模型进行预测
我们已经训练了一个模型并“证明”它是有效的,但在对鸢尾花品种进行分类方面,这还不够。现在,我们使用经过训练的模型对无标签样本(即包含特征但不包含标签的样本)进行一些预测。
在现实生活中,无标签样本可能来自很多不同的来源,包括应用程序、CSV 文件和数据源。暂时我们将手动提供三个无标签样本以预测其标签。回想一下,标签编号会映射到一个指定的表示法:
* `0`:山鸢尾
* `1`:变色鸢尾
* `2`:维吉尼亚鸢尾
```python
predict_dataset = tf.convert_to_tensor([
[5.1, 3.3, 1.7, 0.5,],
[5.9, 3.0, 4.2, 1.5,],
[6.9, 3.1, 5.4, 2.1]
])
predictions = model(predict_dataset)
for i, logits in enumerate(predictions):
class_idx = tf.argmax(logits).numpy()
p = tf.nn.softmax(logits)[class_idx]
name = class_names[class_idx]
print("Example {} prediction: {} ({:4.1f}%)".format(i, name, 100*p))
```
```
Example 0 prediction: Iris setosa (100.0%)
Example 1 prediction: Iris versicolor (100.0%)
Example 2 prediction: Iris virginica (99.5%)
```
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training_walkthrough.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-custom_training_walkthrough.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/custom_training_walkthrough](https://tensorflow.google.cn/beta/tutorials/eager/custom_training_walkthrough)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training_walkthrough.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/custom_training_walkthrough.md)
================================================
FILE: r2/tutorials/eager/tf_function.md
================================================
---
title: tf.function和AutoGraph
categories: tensorflow2官方教程
tags: tensorflow2.0教程
top: 1956
abbrlink: tensorflow/tf2-tutorials-eager-tf_function
---
# tf.function和 AutoGraph 提高性能和可部署性 (tensorflow2.0官方教程翻译)
在TensorFlow 2.0中,默认情况下会打开eager execution,这为您提供了一个非常直观和灵活的用户界面(运行一次性操作更容易,更快)但这可能会牺牲性能和可部署性。
为了获得最佳性能并使您的模型可以在任何地方部署,我们提供了 `tf.function` 作为您可以用来从程序中生成图的工具。多亏了AutoGraph,大量的Python代码可以与tf.function一起工作。但仍有一些陷阱需要警惕。
主要的要点和建议是:
- 不要依赖Python副作用,如对象变异或列表追加。
- tf.function最适合TF操作,而不是NumPy操作或Python原语。
- 如果有疑问,`for x in y` 习语可能会有效。
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
import contextlib
# Some helper code to demonstrate the kinds of errors you might encounter.
@contextlib.contextmanager
def assert_raises(error_class):
try:
yield
except error_class as e:
print('Caught expected exception \n {}: {}'.format(error_class, e))
except Exception as e:
print('Got unexpected exception \n {}: {}'.format(type(e), e))
else:
raise Exception('Expected {} to be raised but no error was raised!'.format(
error_class))
```
你定义的 `tf.function` 就像一个核心TensorFlow操作:你可以急切地执行它,你可以在图中使用它,它有梯度等。
```python
# A function is like an op
@tf.function
def add(a, b):
return a + b
add(tf.ones([2, 2]), tf.ones([2, 2])) # [[2., 2.], [2., 2.]]
```
输出:
```output
<tf.Tensor: id=14, shape=(2, 2), dtype=float32, numpy= array([[2., 2.], [2., 2.]], dtype=float32)>
```
代码
```python
# Functions have gradients
@tf.function
def add(a, b):
return a + b
v = tf.Variable(1.0)
with tf.GradientTape() as tape:
result = add(v, 1.0)
tape.gradient(result, v)
```
输出:
```output
<tf.Tensor: id=40, shape=(), dtype=float32, numpy=1.0>
```
代码
```python
# You can use functions inside functions
@tf.function
def dense_layer(x, w, b):
return add(tf.matmul(x, w), b)
dense_layer(tf.ones([3, 2]), tf.ones([2, 2]), tf.ones([2]))
```
输出:
```output
<tf.Tensor: id=67, shape=(3, 2), dtype=float32, numpy= array([[3., 3.], [3., 3.], [3., 3.]], dtype=float32)>
```
## 1. 追踪和多态性
Python的动态类型意味着您可以使用各种参数类型调用函数,Python将在每个场景中执行不同的操作。
另一方面,TensorFlow图需要静态dtypes和形状尺寸。`tf.function` 通过在必要时回溯函数生成正确的图来弥补这一差距。`tf.function` 使用的大多数微妙之处源于这种回溯行为。
您可以使用不同类型的参数调用函数来查看正在发生的事情。
```python
# Functions are polymorphic
@tf.function
def double(a):
print("Tracing with", a)
return a + a
print(double(tf.constant(1)))
print()
print(double(tf.constant(1.1)))
print()
print(double(tf.constant("a")))
print()
```
输出:
```output
Tracing with Tensor("a:0", shape=(), dtype=int32) tf.Tensor(2, shape=(), dtype=int32)
Tracing with Tensor("a:0", shape=(), dtype=float32) tf.Tensor(2.2, shape=(), dtype=float32)
Tracing with Tensor("a:0", shape=(), dtype=string) tf.Tensor(b'aa', shape=(), dtype=string)
```
要控制跟踪行为,请使用以下技术:
- 创建一个新的`tf.function`:保证单独的`tf.function`对象不共享跟踪。
- 使用`get_concrete_function`方法获取特定的跟踪
- 调用`tf.function`时指定`input_signature`以确保只构建一个函数图
```python
print("Obtaining concrete trace")
double_strings = double.get_concrete_function(tf.TensorSpec(shape=None, dtype=tf.string))
print("Executing traced function")
print(double_strings(tf.constant("a")))
print(double_strings(a=tf.constant("b")))
print("Using a concrete trace with incompatible types will throw an error")
with assert_raises(tf.errors.InvalidArgumentError):
double_strings(tf.constant(1))
```
```python
@tf.function(input_signature=(tf.TensorSpec(shape=[None], dtype=tf.int32),))
def next_collatz(x):
print("Tracing with", x)
return tf.where(tf.equal(x % 2, 0), x // 2, 3 * x + 1)
print(next_collatz(tf.constant([1, 2])))
# We specified a 1-D tensor in the input signature, so this should fail.
with assert_raises(ValueError):
next_collatz(tf.constant([[1, 2], [3, 4]]))
```
## 2. 什么时候回溯?
多态 `tf.function` 保持跟踪生成的具体函数的缓存。缓存键实际上是从函数args和kwargs生成的键的元组。为`tf.Tensor`参数生成的关键是它的形状和类型。为Python原语生成的密钥是它的值。对于所有其他Python类型,键基于对象`id()`,以便为每个类的实例独立跟踪方法。将来,TensorFlow可以为Python对象添加更复杂的缓存,可以安全地转换为张量。
## 3. Python还是Tensor args?
通常,Python参数用于控制超参数和图构造。例如,`num_layers = 10 `或 `training = True` 或`nonlinearity ='relu'`。因此,如果Python参数发生变化,那么您必须回溯图形是有道理的。
但是,Python参数可能不会用于控制图构造。在这些情况下,Python值的变化可能会触发不必要的回溯。举例来说,这个训练循环,AutoGraph将动态展开。尽管存在多个跟踪,但生成的图实际上是相同的,因此这有点低效。
```python
def train_one_step():
pass
@tf.function
def train(num_steps):
print("Tracing with num_steps = {}".format(num_steps))
for _ in tf.range(num_steps):
train_one_step()
train(num_steps=10)
train(num_steps=20)
```
输出:
```output
Tracing with num_steps = 10 Tracing with num_steps = 20
```
如果它们不影响生成的图的形状,简单的解决方法是将参数转换为Tensors。
```python
train(num_steps=tf.constant(10))
train(num_steps=tf.constant(20))
```
输出:
```output
Tracing with num_steps = Tensor("num_steps:0", shape=(), dtype=int32)
```
## 4. `tf.function`中的副作用
> “副作用” 指在满足主要功能(主作用?)的同时,顺便完成了一些其他的副要功能”,也可翻译为“附作用”
通常,Python附作用(如打印或变异对象)仅在跟踪期间发生。那你如何可靠地触发`tf.function`的附作用呢?
一般的经验法则是仅使用Python副作用来调试跟踪。另外,TensorFlow操作如`tf.Variable.assign`,`tf.print`和`tf.summary`是确保TensorFlow运行时,在每次调用时,跟踪和执行代码的最佳方法。通常使用函数样式将产生最佳效果。
```python
@tf.function
def f(x):
print("Traced with", x)
tf.print("Executed with", x)
f(1)
f(1)
f(2)
```
输出:
```output
Traced with 1 Executed with 1 Executed with 1
Traced with 2 Executed with 2
```
如果你想在每次调用 `tf.function` 期间执行Python代码,`tf.py_function`就是一个退出舱口。`tf.py_function`的缺点是它不可移植或特别高效,也不能在分布式(多GPU,TPU)设置中很好地工作。此外,由于必须将`tf.py_function`连接到图中,它会将所有输入/输出转换为张量。
```python
external_list = []
def side_effect(x):
print('Python side effect')
external_list.append(x)
@tf.function
def f(x):
tf.py_function(side_effect, inp=[x], Tout=[])
f(1)
f(1)
f(1)
assert len(external_list) == 3
# .numpy() call required because py_function casts 1 to tf.constant(1)
assert external_list[0].numpy() == 1
```
## 5. 谨防Python状态
许多Python功能(如生成器和迭代器)依赖于Python运行时来跟踪状态。通常,虽然这些构造在Eager模式下按预期工作,但由于跟踪行为,在`tf.function`中会发生许多意外情况。
举一个例子,推进迭代器状态是一个Python副作用,因此只在跟踪期间发生。
```python
external_var = tf.Variable(0)
@tf.function
def buggy_consume_next(iterator):
external_var.assign_add(next(iterator))
tf.print("Value of external_var:", external_var)
iterator = iter([0, 1, 2, 3])
buggy_consume_next(iterator)
# This reuses the first value from the iterator, rather than consuming the next value.
buggy_consume_next(iterator)
buggy_consume_next(iterator)
```
如果在tf.function中生成并完全使用了迭代器,那么它应该可以正常工作。但是,整个迭代器可能正在被跟踪,这可能导致一个巨大的图。这可能就是你想要的。但是如果你正在训练一个表示为Python列表的大型内存数据集,那么这可以生成一个非常大的图,并且`tf.function`不太可能产生加速。
如果你想迭代Python数据,最安全的方法是将它包装在tf.data.Dataset中并使用`for x in y`惯用法。当`y`是张量或tf.data.Dataset时,AutoGraph特别支持安全地转换`for`循环。
```python
def measure_graph_size(f, *args):
g = f.get_concrete_function(*args).graph
print("{}({}) contains {} nodes in its graph".format(
f.__name__, ', '.join(map(str, args)), len(g.as_graph_def().node)))
@tf.function
def train(dataset):
loss = tf.constant(0)
for x, y in dataset:
loss += tf.abs(y - x) # Some dummy computation.
return loss
small_data = [(1, 1)] * 2
big_data = [(1, 1)] * 10
measure_graph_size(train, small_data)
measure_graph_size(train, big_data)
measure_graph_size(train, tf.data.Dataset.from_generator(
lambda: small_data, (tf.int32, tf.int32)))
measure_graph_size(train, tf.data.Dataset.from_generator(
lambda: big_data, (tf.int32, tf.int32)))
```
在数据集中包装Python / Numpy数据时,请注意 `tf.data.Dataset.from_generator` 与 `tf.data.Dataset.from_tensors`。前者将数据保存在Python中并通过 `tf.py_function` 获取,这可能会影响性能,而后者会将数据的副本捆绑为图中的一个大的 `tf.constant()` 节点,这可以有记忆含义。
通过 TFRecordDataset/CsvDataset等从文件中读取数据,是最有效的数据消费方式,因为TensorFlow本身可以管理数据的异步加载和预取,而不必涉及Python。
## 6. 自动控制依赖项
在一般数据流图上,作为编程模型的函数,一个非常吸引人的特性是函数可以为运行时提供有关代码预期行为的更多信息。
例如,当编写具有多个读取和写入相同变量的代码时,数据流图可能不会自然地编码最初预期的操作顺序。在`tf.function`中,我们通过引用原始Python代码中语句的执行顺序来解决执行顺序中的歧义。这样,`tf.function` 中的有状态操作的排序复制了Eager模式的语义。
这意味着不需要添加手动控制依赖项;`tf.function`非常智能,可以为代码添加最小的必要和足够的控制依赖关系,以便正确运行。
```python
# Automatic control dependencies
a = tf.Variable(1.0)
b = tf.Variable(2.0)
@tf.function
def f(x, y):
a.assign(y * b)
b.assign_add(x * a)
return a + b
f(1.0, 2.0) # 10.0
```
输出:
```output
<tf.Tensor: id=466, shape=(), dtype=float32, numpy=10.0>
```
## 7. 变量
我们可以使用相同的想法来利用代码的预期执行顺序,以便在`tf.function`中非常容易地创建和使用变量。但是有一个非常重要的警告,即使用变量,可以编写在急切模式和图形模式下表现不同的代码。
具体来说,每次调用创建一个新变量时都会发生这种情况。由于跟踪语义,`tf.function`将在每次调用时重用相同的变量,但是eager模式将在每次调用时创建一个新变量。为了防止这个错误,`tf.function`会在检测到危险变量创建行为时引发错误。
```python
@tf.function
def f(x):
v = tf.Variable(1.0)
v.assign_add(x)
return v
with assert_raises(ValueError):
f(1.0)
```
输出:
```output
Caught expected exception <class 'ValueError'>: tf.function-decorated function tried to create variables on non-first call.
```
```python
# Non-ambiguous code is ok though
v = tf.Variable(1.0)
@tf.function
def f(x):
return v.assign_add(x)
print(f(1.0)) # 2.0
print(f(2.0)) # 4.0
```
输出:
```output
tf.Tensor(2.0, shape=(), dtype=float32)
tf.Tensor(4.0, shape=(), dtype=float32)
```
```python
# You can also create variables inside a tf.function as long as we can prove
# that those variables are created only the first time the function is executed.
class C: pass
obj = C(); obj.v = None
@tf.function
def g(x):
if obj.v is None:
obj.v = tf.Variable(1.0)
return obj.v.assign_add(x)
print(g(1.0)) # 2.0
print(g(2.0)) # 4.0
```
输出:
```output
tf.Tensor(2.0, shape=(), dtype=float32)
tf.Tensor(4.0, shape=(), dtype=float32)
```
```python
# Variable initializers can depend on function arguments and on values of other
# variables. We can figure out the right initialization order using the same
# method we use to generate control dependencies.
state = []
@tf.function
def fn(x):
if not state:
state.append(tf.Variable(2.0 * x))
state.append(tf.Variable(state[0] * 3.0))
return state[0] * x * state[1]
print(fn(tf.constant(1.0)))
print(fn(tf.constant(3.0)))
```
输出:
```output
tf.Tensor(12.0, shape=(), dtype=float32)
tf.Tensor(36.0, shape=(), dtype=float32)
```
# 使用 AutoGraph
[autograph](https://www.tensorflow.org/guide/autograph) 库与`tf.function`完全集成,它将重写依赖于Tensors的条件和循环,以便在图中动态运行。
`tf.cond`和`tf.while_loop`继续使用`tf.function`,但是当以命令式方式编写时,具有控制流的代码通常更容易编写和理解。
```python
# Simple loop
@tf.function
def f(x):
while tf.reduce_sum(x) > 1:
tf.print(x)
x = tf.tanh(x)
return x
f(tf.random.uniform([5]))
```
```python
# If you're curious you can inspect the code autograph generates.
# It feels like reading assembly language, though.
def f(x):
while tf.reduce_sum(x) > 1:
tf.print(x)
x = tf.tanh(x)
return x
print(tf.autograph.to_code(f))
```
## 8. AutoGraph:条件
AutoGraph会将`if`语句转换为等效的`tf.cond`调用。
如果条件是Tensor,则进行此替换。否则,在跟踪期间执行条件。
```python
def test_tf_cond(f, *args):
g = f.get_concrete_function(*args).graph
if any(node.name == 'cond' for node in g.as_graph_def().node):
print("{}({}) uses tf.cond.".format(
f.__name__, ', '.join(map(str, args))))
else:
print("{}({}) executes normally.".format(
f.__name__, ', '.join(map(str, args))))
```
```python
@tf.function
def hyperparam_cond(x, training=True):
if training:
x = tf.nn.dropout(x, rate=0.5)
return x
@tf.function
def maybe_tensor_cond(x):
if x < 0:
x = -x
return x
test_tf_cond(hyperparam_cond, tf.ones([1], dtype=tf.float32))
test_tf_cond(maybe_tensor_cond, tf.constant(-1))
test_tf_cond(maybe_tensor_cond, -1)
```
`tf.cond`有许多微妙之处。
- 它的工作原理是跟踪条件的两边,然后根据条件在运行时选择适当的分支。跟踪双方可能导致意外执行Python代码
- 它要求如果一个分支创建下游使用的张量,另一个分支也必须创建该张量。
```python
@tf.function
def f():
x = tf.constant(0)
if tf.constant(True):
x = x + 1
print("Tracing `then` branch")
else:
x = x - 1
print("Tracing `else` branch")
return x
f()
```
```python
@tf.function
def f():
if tf.constant(True):
x = tf.ones([3, 3])
return x
# Throws an error because both branches need to define `x`.
with assert_raises(ValueError):
f()
```
## 9. AutoGraph和循环
AutoGraph有一些简单的转换循环规则。
- `for`: 如果iterable是张量,则转换
- `while`: 如果while条件取决于张量,则转换
如果转换了循环,它将使用`tf.while_loop`动态展开,或者在 `for x in tf.data.Dataset` 的特殊情况下,转换为 `tf.data.Dataset.reduce`。
如果未转换循环,则将静态展开。
```python
def test_dynamically_unrolled(f, *args):
g = f.get_concrete_function(*args).graph
if any(node.name == 'while' for node in g.as_graph_def().node):
print("{}({}) uses tf.while_loop.".format(
f.__name__, ', '.join(map(str, args))))
elif any(node.name == 'ReduceDataset' for node in g.as_graph_def().node):
print("{}({}) uses tf.data.Dataset.reduce.".format(
f.__name__, ', '.join(map(str, args))))
else:
print("{}({}) gets unrolled.".format(
f.__name__, ', '.join(map(str, args))))
```
```python
@tf.function
def for_in_range():
x = 0
for i in range(5):
x += i
return x
@tf.function
def for_in_tfrange():
x = tf.constant(0, dtype=tf.int32)
for i in tf.range(5):
x += i
return x
@tf.function
def for_in_tfdataset():
x = tf.constant(0, dtype=tf.int64)
for i in tf.data.Dataset.range(5):
x += i
return x
test_dynamically_unrolled(for_in_range)
test_dynamically_unrolled(for_in_tfrange)
test_dynamically_unrolled(for_in_tfdataset)
```
输出:
```output
for_in_range() gets unrolled.
for_in_tfrange() uses tf.while_loop.
for_in_tfdataset() uses tf.data.Dataset.reduce.
```
```python
@tf.function
def while_py_cond():
x = 5
while x > 0:
x -= 1
return x
@tf.function
def while_tf_cond():
x = tf.constant(5)
while x > 0:
x -= 1
return x
test_dynamically_unrolled(while_py_cond)
test_dynamically_unrolled(while_tf_cond)
```
输出:
```output
while_py_cond() gets unrolled.
while_tf_cond() uses tf.while_loop.
```
如果你有一个取决于张量的`break`或早期`return`子句,那么顶级条件或者iterable也应该是一个张量。
```python
@tf.function
def buggy_while_py_true_tf_break(x):
while True:
if tf.equal(x, 0):
break
x -= 1
return x
@tf.function
def while_tf_true_tf_break(x):
while tf.constant(True):
if tf.equal(x, 0):
break
x -= 1
return x
with assert_raises(TypeError):
test_dynamically_unrolled(buggy_while_py_true_tf_break, 5)
test_dynamically_unrolled(while_tf_true_tf_break, 5)
@tf.function
def buggy_py_for_tf_break():
x = 0
for i in range(5):
if tf.equal(i, 3):
break
x += i
return x
@tf.function
def tf_for_tf_break():
x = 0
for i in tf.range(5):
if tf.equal(i, 3):
break
x += i
return x
with assert_raises(TypeError):
test_dynamically_unrolled(buggy_py_for_tf_break)
test_dynamically_unrolled(tf_for_tf_break)
```
为了累积动态展开循环的结果,你需要使用`tf.TensorArray`。
```python
batch_size = 2
seq_len = 3
feature_size = 4
def rnn_step(inp, state):
return inp + state
@tf.function
def dynamic_rnn(rnn_step, input_data, initial_state):
# [batch, time, features] -> [time, batch, features]
input_data = tf.transpose(input_data, [1, 0, 2])
max_seq_len = input_data.shape[0]
states = tf.TensorArray(tf.float32, size=max_seq_len)
state = initial_state
for i in tf.range(max_seq_len):
state = rnn_step(input_data[i], state)
states = states.write(i, state)
return tf.transpose(states.stack(), [1, 0, 2])
dynamic_rnn(rnn_step,
tf.random.uniform([batch_size, seq_len, feature_size]),
tf.zeros([batch_size, feature_size]))
```
与`tf.cond`一样,`tf.while_loop`也带有许多细微之处。
- 由于循环可以执行0次,因此必须在循环上方初始化在while_loop下游使用的所有张量
- 所有循环变量的shape/dtypes必须与每次迭代保持一致
```python
@tf.function
def buggy_loop_var_uninitialized():
for i in tf.range(3):
x = i
return x
@tf.function
def f():
x = tf.constant(0)
for i in tf.range(3):
x = i
return x
with assert_raises(ValueError):
buggy_loop_var_uninitialized()
f()
```
```python
@tf.function
def buggy_loop_type_changes():
x = tf.constant(0, dtype=tf.float32)
for i in tf.range(3): # Yields tensors of type tf.int32...
x = i
return x
with assert_raises(tf.errors.InvalidArgumentError):
buggy_loop_type_changes()
```
```python
@tf.function
def buggy_concat():
x = tf.ones([0, 10])
for i in tf.range(5):
x = tf.concat([x, tf.ones([1, 10])], axis=0)
return x
with assert_raises(ValueError):
buggy_concat()
@tf.function
def concat_with_padding():
x = tf.zeros([5, 10])
for i in tf.range(5):
x = tf.concat([x[:i], tf.ones([1, 10]), tf.zeros([4-i, 10])], axis=0)
x.set_shape([5, 10])
return x
concat_with_padding()
```
## 10. 下一步
现在重新访问早期的教程并尝试使用 `tf.function` 加速代码!
> 最新版本:[https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-tf_function.html](https://www.mashangxue123.com/tensorflow/tf2-tutorials-eager-tf_function.html)
> 英文版本:[https://tensorflow.google.cn/beta/tutorials/eager/tf_function](https://tensorflow.google.cn/beta/tutorials/eager/tf_function)
> 翻译建议PR:[https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/tf_function.md](https://github.com/mashangxue/tensorflow2-zh/edit/master/r2/tutorials/eager/tf_function.md)
================================================
FILE: r2/tutorials/estimators/linear.md
================================================
---
title: 使用 Estimator 构建线性模型
tags:
- tensorflow2.0
categories:
- tensorflow2官方教程
top: 1929
abbrlink: tensorflow/tf2-tutorials-estimators-linear
---
# 使用 Estimator 构建线性模型
## 1. 概述
这个端到端的演练使用`tf.estimator` API训练逻辑回归模型。该模型通常用作其他更复杂算法的基准。
Estimator 是可扩展性最强且面向生产的 TensorFlow 模型类型。如需了解详情,请参阅 [Estimator 指南](https://www.tensorflow.org/guide/estimators)。
## 2. 安装和导入
安装sklearn命令: `pip install sklearn`
```python
from __future__ import absolute_import, division, print_function, unicode_literals
import os
import sys
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import clear_output
from six.moves import urllib
```
## 3. 加载泰坦尼克号数据集
您将使用泰坦尼克数据集,其以预测乘客的生存(相当病态)为目标,给出性别、年龄、阶级等特征。
```python
import tensorflow.compat.v2.feature_column as fc
import tensorflow as tf
# 加载数据集
dftrain = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/train.csv')
dfeval = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/eval.csv')
y_train = dftrain.pop('survived')
y_eval = dfeval.pop('survived')
```
## 4. 探索数据
数据集包含以下特征:
```python
dftrain.head()
```
| | sex | age | n_siblings_spouses | parch | fare | class | deck | embark_town | alone |
|---|--------|------|--------------------|-------|---------|-------|---------|-------------|-------|
| 0 | male | 22.0 | 1 | 0 | 7.2500 | Third | unknown | Southampton | n |
| 1 | female | 38.0 | 1 | 0 | 71.2833 | First | C | Cherbourg | n |
| 2 | female | 26.0 | 0 | 0 | 7.9250 | Third | unknown | Southampton | y |
| 3 | female | 35.0 | 1 | 0 | 53.1000 | First | C | Southampton | n |
| 4 | male | 28.0 | 0 | 0 | 8.4583 | Third | unknown | Queenstown | y |
```python
dftrain.describe()
```
| | age | n_siblings_spouses | parch | fare |
|-------|------------|--------------------|------------|------------|
| count | 627.000000 | 627.000000 | 627.000000 | 627.000000 |
| mean | 29.631308 | 0.545455 | 0.379585 | 34.385399 |
| std | 12.511818 | 1.151090 | 0.792999 | 54.597730 |
| min | 0.750000 | 0.000000 | 0.000000 | 0.000000 |
| 25% | 23.000000 | 0.000000 | 0.000000 | 7.895800 |
| 50% | 28.000000 | 0.000000 | 0.000000 | 15.045800 |
| 75% | 35.000000 | 1.000000 | 0.000000 | 31.387500 |
| max | 80.000000 | 8.000000 | 5.000000 | 512.329200 |
训练和评估集分别有627和264个样本数据:
```python
dftrain.shape[0], dfeval.shape[0]
```
```
(627, 264)
```
大多数乘客都在20和30年代
```python
dftrain.age.hist(bins=20)
```

机上的男性乘客大约是女性乘客的两倍。
```python
dftrain.sex.value_counts().plot(kind='barh')
```

大多数乘客都在“第三”阶级:
```python
dftrain['class'].value_counts().plot(kind='barh')
```

与男性相比,女性的生存机会要高得多,这显然是该模型的预测特征:
```python
pd.concat([dftrain, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh').set_xlabel('% survive')
```

## 5. 模型的特征工程
Estimator使用称为[特征列](https://www.tensorflow.org/guide/feature_columns)的系统来描述模型应如何解释每个原始输入特征,Estimator需要一个数字输入向量,而特征列描述模型应如何转换每个特征。
选择和制作正确的特征列是学习有效模型的关键,特征列可以是原始特征`dict`(基本特征列)中的原始输入之一,也可以是使用在一个或多个基本列(派生特征列)上定义的转换创建的任何新列。
线性Estimator同时使用数值和分类特征,特征列适用于所有TensorFlow Estimator,它们的目的是定义用于建模的特征。此外,它们还提供了一些特征工程功能,比如独热编码、归一化和分桶。
### 5.1. 基本特征列
```python
CATEGORICAL_COLUMNS = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck',
'embark_town', 'alone']
NUMERIC_COLUMNS = ['age', 'fare']
feature_columns = []
for feature_name in CATEGORICAL_COLUMNS:
vocabulary = dftrain[feature_name].unique()
feature_columns.append(tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary))
for feature_name in NUMERIC_COLUMNS:
feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))
```
`input_function`指定如何将数据转换为以流方式提供输入管道的`tf.data.Dataset`。`tf.data.Dataset`采用多种来源,如数据帧DataFrame,csv格式的文件等。
```python
def make_input_fn(data_df, label_df, num_epochs=10, shuffle=True, batch_size=32):
def input_function():
ds = tf.data.Dataset.from_tensor_slices((dict(data_df), label_df))
if shuffle:
ds = ds.shuffle(1000)
ds = ds.batch(batch_size).repeat(num_epochs)
return ds
return input_function
train_input_fn = make_input_fn(dftrain, y_train)
eval_input_fn = make_input_fn(dfeval, y_eval, num_epochs=1, shuffle=False)
```
检查数据集:
```python
ds = make_input_fn(dftrain, y_train, batch_size=10)()
for feature_batch, label_batch in ds.take(1):
print('Some feature keys:', list(feature_batch.keys()))
print()
print('A batch of class:', feature_batch['class'].numpy())
print()
print('A batch of Labels:', label_batch.numpy())
```
您还可以使用`tf.keras.layers.DenseFeatures`层检查特征列的结果:
```python
age_column = feature_columns[7]
tf.keras.layers.DenseFeatures([age_column])(feature_batch).numpy()
```
```
array([[38.],
[39.],
[28.],
[28.],
[36.],
[71.],
[24.],
[47.],
[23.],
[28.]], dtype=float32)
```
`DenseFeatures`只接受密集张量,要检查分类列,需要先将其转换为指示列:
```python
gender_column = feature_columns[0]
tf.keras.layers.DenseFeatures([tf.feature_column.indicator_column(gender_column)])(feature_batch).numpy()
```
```
array([[0., 1.],
[0., 1.],
[1., 0.],
[0., 1.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[1., 0.],
[0., 1.]], dtype=float32)
```
将所有基本特征添加到模型后,让我们训练模型。使用`tf.estimator` API训练模型只是一个命令:
```python
linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns)
linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)
clear_output()
print(result)
```
```
{'accuracy_baseline': 0.625, 'auc': 0.83722067, 'accuracy': 0.7462121, 'recall': 0.6666667, 'global_step': 200, 'prediction/mean': 0.38311505, 'average_loss': 0.47361037, 'precision': 0.66, 'auc_precision_recall': 0.7851523, 'loss': 0.46608958, 'label/mean': 0.375}
```
### 5.2. 派生特征列
现在你达到了75%的准确率。单独使用每个基本功能列可能不足以解释数据。例如,性别和标签之间的相关性可能因性别不同而不同。因此,如果您只学习`gender="Male"`和`gender="Female"`的单一模型权重,您将无法捕捉每个年龄-性别组合(例如,区分`gender
gitextract_ecdkfdrh/
├── README.md
└── r2/
├── guide/
│ ├── eager.md
│ ├── effective_tf2.md
│ ├── keras/
│ │ ├── functional.md
│ │ ├── overview.md
│ │ └── training_and_evaluation.md
│ └── migration_guide.md
└── tutorials/
├── eager/
│ ├── automatic_differentiation.md
│ ├── basics.md
│ ├── custom_layers.md
│ ├── custom_training.md
│ ├── custom_training_walkthrough.md
│ └── tf_function.md
├── estimators/
│ └── linear.md
├── images/
│ ├── hub_with_keras.md
│ ├── intro_to_cnns.md
│ ├── segmentation.md
│ └── transfer_learning.md
├── keras/
│ ├── basic_classification.md
│ ├── basic_regression.md
│ ├── basic_text_classification.md
│ ├── basic_text_classification_with_tfhub.md
│ ├── feature_columns.md
│ ├── overfit_and_underfit.md
│ └── save_and_restore_models.md
├── quickstart/
│ ├── advanced.md
│ └── beginner.md
└── text/
├── image_captioning.md
├── nmt_with_attention.md
├── text_classification_rnn.md
├── text_generation.md
├── transformer.md
└── word_embeddings.md
Condensed preview — 33 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (585K chars).
[
{
"path": "README.md",
"chars": 16951,
"preview": "---\ntitle: tensorflow2官方教程目录导航\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1900\nabbrlink: tensorflow/tensorfl"
},
{
"path": "r2/guide/eager.md",
"chars": 15001,
"preview": "---\ntitle: Eager Execution 概述\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1999\nabbrlink: tensorflow/tf2-guide"
},
{
"path": "r2/guide/effective_tf2.md",
"chars": 8529,
"preview": "---\ntitle: 高效的TensorFlow 2.0\ntags: \n - tensorflow2.0\ncategories: \n - tensorflow2官方教程\ntop: 1902\nabbrlink: tensorflo"
},
{
"path": "r2/guide/keras/functional.md",
"chars": 23070,
"preview": "---\ntitle: 不用Sequential模型,TensorFlow中的Keras函数式API\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1999\nabbrlink: "
},
{
"path": "r2/guide/keras/overview.md",
"chars": 17963,
"preview": "---\ntitle: Keras概述:构建模型,输入数据,训练,评估,回调\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1999\nabbrlink: tensorflow/t"
},
{
"path": "r2/guide/keras/training_and_evaluation.md",
"chars": 33477,
"preview": "---\ntitle: 使用 TensorFlow Keras 进行训练和评估\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1999\nabbrlink: tensorflow/"
},
{
"path": "r2/guide/migration_guide.md",
"chars": 21868,
"preview": "---\ntitle: 将 TF1.x 代码迁移到 TensorFlow 2.0\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1903\nabbrlink: tensorflow"
},
{
"path": "r2/tutorials/eager/automatic_differentiation.md",
"chars": 3514,
"preview": "---\ntitle: TF梯度下降法的核心自动微分和梯度带\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1953\nabbrlink: tensorflow/tf2-tutor"
},
{
"path": "r2/tutorials/eager/basics.md",
"chars": 6374,
"preview": "---\ntitle: tensorflow2.0张量及其操作、numpy兼容、GPU加速\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1951\nabbrlink: tenso"
},
{
"path": "r2/tutorials/eager/custom_layers.md",
"chars": 5572,
"preview": "---\ntitle: 使用Keras自定义层\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1952\nabbrlink: tensorflow/tf2-tutorials-ea"
},
{
"path": "r2/tutorials/eager/custom_training.md",
"chars": 4733,
"preview": "---\ntitle: 构建tensorflow2.0模型自定义训练的基础步骤\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1954\nabbrlink: tensorflow/"
},
{
"path": "r2/tutorials/eager/custom_training_walkthrough.md",
"chars": 17436,
"preview": "---\ntitle: 使用Keras演示TensorFlow2.0自定义训练实战\ntags: \n - tensorflow2.0\ncategories: \n - tensorflow2官方教程\ntop: 1955\nabbrlin"
},
{
"path": "r2/tutorials/eager/tf_function.md",
"chars": 16872,
"preview": "---\ntitle: tf.function和AutoGraph\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1956\nabbrlink: tensorflow/tf2-tu"
},
{
"path": "r2/tutorials/estimators/linear.md",
"chars": 8856,
"preview": "---\ntitle: 使用 Estimator 构建线性模型\ntags: \n - tensorflow2.0\ncategories: \n - tensorflow2官方教程\ntop: 1929\nabbrlink: tensorf"
},
{
"path": "r2/tutorials/images/hub_with_keras.md",
"chars": 10077,
"preview": "---\ntitle: 基于Keras使用TensorFlow Hub实现迁移学习\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1922\nabbrlink: tensorflo"
},
{
"path": "r2/tutorials/images/intro_to_cnns.md",
"chars": 5747,
"preview": "---\ntitle: 使用TF2.0实现卷积神经网络CNN对MNIST数字分类\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1921\nabbrlink: tensorflow"
},
{
"path": "r2/tutorials/images/segmentation.md",
"chars": 8747,
"preview": "---\ntitle: 图像分割\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1924\nabbrlink: tensorflow/tf2-tutorials-images-in"
},
{
"path": "r2/tutorials/images/transfer_learning.md",
"chars": 14474,
"preview": "---\ntitle: 使用预训练的卷积神经网络进行迁移学习\ntags: tensorflow2.0教程\ncategories: tensorflow2官方教程\ntop: 1923\nabbrlink: tensorflow/tf2-tutor"
},
{
"path": "r2/tutorials/keras/basic_classification.md",
"chars": 10107,
"preview": "---\ntitle: 训练您的第一个神经网络:基本分类Fashion MNIST\ncategories: \n - tensorflow2官方教程\ntags: \n - tensorflow2.0\ntop: 1911\nabbrlin"
},
{
"path": "r2/tutorials/keras/basic_regression.md",
"chars": 12442,
"preview": "---\ntitle: 回归项目实战:预测燃油效率\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1914\nabbrlink: tensorflow/tf2-tutorials-"
},
{
"path": "r2/tutorials/keras/basic_text_classification.md",
"chars": 9346,
"preview": "---\ntitle: 文本分类项目实战:电影评论\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1927\nabbrlink: tensorflow/tf2-tutorials-"
},
{
"path": "r2/tutorials/keras/basic_text_classification_with_tfhub.md",
"chars": 6627,
"preview": "---\ntitle: 使用Keras和TensorFlow Hub对电影评论进行文本分类\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1918\nabbrlink: tenso"
},
{
"path": "r2/tutorials/keras/feature_columns.md",
"chars": 11885,
"preview": "---\ntitle: 结构化数据分类实战:心脏病预测\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1913\nabbrlink: tensorflow/tf2-tutorial"
},
{
"path": "r2/tutorials/keras/overfit_and_underfit.md",
"chars": 14183,
"preview": "---\ntitle: 探索过拟合和欠拟合\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1915\nabbrlink: tensorflow/tf2-tutorials-kera"
},
{
"path": "r2/tutorials/keras/save_and_restore_models.md",
"chars": 11570,
"preview": "---\ntitle: tensorflow2保存和加载模型\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1916\nabbrlink: tensorflow/tf2-tutor"
},
{
"path": "r2/tutorials/quickstart/advanced.md",
"chars": 4099,
"preview": "---\ntitle: 专家入门TensorFlow 2.0\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1906\nabbrlink: tensorflow/tf2-tutor"
},
{
"path": "r2/tutorials/quickstart/beginner.md",
"chars": 1738,
"preview": "---\ntitle: 初学者入门 TensorFlow 2.0\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1905\nabbrlink: tensorflow/tf2-tut"
},
{
"path": "r2/tutorials/text/image_captioning.md",
"chars": 19335,
"preview": "---\ntitle: 使用注意力机制给图片取标题\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1963\nabbrlink: tensorflow/tf2-tutorials-"
},
{
"path": "r2/tutorials/text/nmt_with_attention.md",
"chars": 19819,
"preview": "---\ntitle: 采用注意力机制的神经机器翻译\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1962\nabbrlink: tensorflow/tf2-tutorials"
},
{
"path": "r2/tutorials/text/text_classification_rnn.md",
"chars": 7792,
"preview": "---\ntitle: 使用RNN对文本进行分类实践:电影评论\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1928\nabbrlink: tensorflow/tf2-tuto"
},
{
"path": "r2/tutorials/text/text_generation.md",
"chars": 20058,
"preview": "---\ntitle: 使用RNN生成文本实战:莎士比亚风格诗句\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1961\nabbrlink: tensorflow/tf2-tut"
},
{
"path": "r2/tutorials/text/transformer.md",
"chars": 47520,
"preview": "---\ntitle: 用于语言理解的变换器模型\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1964\nabbrlink: tensorflow/tf2-tutorials-t"
},
{
"path": "r2/tutorials/text/word_embeddings.md",
"chars": 10727,
"preview": "---\ntitle: NLP词嵌入Word embedding实战项目\ncategories: tensorflow2官方教程\ntags: tensorflow2.0教程\ntop: 1926\nabbrlink: tensorflow/tf2"
}
]
About this extraction
This page contains the full source code of the mashangxue/tensorflow2-zh GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 33 files (436.0 KB), approximately 150.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.