Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/zh-cn/guide/basics.ipynb
25115 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

TensorFlow 基础知识

本指南提供TensorFlow 基础知识的快速概览。本文档的每个部分都是对一个大主题的概述——您可以在每个部分的末尾找到指向完整指南的链接。

TensorFlow 是一个端到端的机器学习平台。它支持以下内容:

  • 基于多维数组的数值计算(类似于NumPy 。)

  • GPU 和分布式处理

  • 自动微分

  • 模型构造、训练和导出

  • 及更多内容

张量

TensorFlow 对tf.Tensor对象表示的多维数组或张量进行运算。下面一个二维张量:

import tensorflow as tf x = tf.constant([[1., 2., 3.], [4., 5., 6.]]) print(x) print(x.shape) print(x.dtype)

tf.Tensor最重要的属性是它的shape(形状)和dtype(数据类型) :

  • Tensor.shape :表示张量每个轴上的大小。

  • Tensor.dtype :表示张量中所有元素的类型。

TensorFlow 实现了对张量的标准数学运算,以及许多机器学习的专用操作。

例如:

x + x
5 * x
x @ tf.transpose(x)
tf.concat([x, x, x], axis=0)
tf.nn.softmax(x, axis=-1)
tf.reduce_sum(x)

注:通常,在 TensorFlow 函数需要 Tensor 作为输入的任何地方,该函数也将接受可使用 tf.convert_to_tensor 转换为 Tensor 的任何内容。请参见下面的示例。

tf.convert_to_tensor([1,2,3])
tf.reduce_sum([1,2,3])

在 CPU 上运行大型计算可能会很慢。配置正确的 TensorFlow 可以使用 GPU 等加速硬件非常快速地运算。

if tf.config.list_physical_devices('GPU'): print("TensorFlow **IS** using the GPU") else: print("TensorFlow **IS NOT** using the GPU")

详情参阅 Tensor guide (张量指南)。

变量

普通的tf.Tensor对象是不可变的。要在 TensorFlow 中存储模型权重(或其他可变状态),请使用tf.Variable

var = tf.Variable([0.0, 0.0, 0.0])
var.assign([1, 2, 3])
var.assign_add([1, 1, 1])

详见 Variables guide (变量指南)。

自动微分

Gradient descent(梯度下降)及相关算法是现代机器学习的基础。

为此,TensorFlow 实现了自动微分 (autodiff),它使用微积分来计算梯度。通常用它来计算模型基于其权重的误差损失的梯度。

x = tf.Variable(1.0) def f(x): y = x**2 + 2*x - 5 return y
f(x)

x = 1.0, y = f(x) = (1**2 + 2*1 - 5) = -2.

y的导数是 y' = f'(x) = (2*x + 2) = 4 。 TensorFlow 可以自动计算:

with tf.GradientTape() as tape: y = f(x) g_x = tape.gradient(y, x) # g(x) = dy/dx g_x

这个简化的例子只对单个标量 ( x ) 求导,但 TensorFlow 可以同时计算任意数量的非标量张量的梯度。

详见 Autodiff guide (自动微分)。

图和 tf.function装饰器

TensorFlow 可以像任何 Python 库一样以交互方式使用,同时还提供以下工具:

  • 性能优化:加速训练和推理。

  • 导出:保存训练好的模型。

这就要用 tf.function 装饰器将纯 TensorFlow 代码与普通 Python 代码隔离开来。

@tf.function def my_func(x): print('Tracing.\n') return tf.reduce_sum(x)

第一次运行由tf.function装饰的函数时,虽然它在 Python 中执行,但它会取得一个经由 TensorFlow 计算的完整优化图。

x = tf.constant([1, 2, 3]) my_func(x)

在后续调用中,TensorFlow 仅执行优化图,跳过所有非 TensorFlow 步骤。注意下面的my_func不打印Tracing,因为print是 Python 函数,而不是 TensorFlow 函数。

x = tf.constant([10, 9, 8]) my_func(x)

输入的签名shapedtype )不同,就不能使用原来的图,要生成一个新图:

x = tf.constant([10.0, 9.1, 8.2], dtype=tf.float32) my_func(x)

这些取得的图提供了两个好处:

  • 在许多情况下,显著提升了执行速度(虽然在上面这个例子中无关紧要)。

  • 可以用tf.saved_model导出这些图,以便在服务器移动设备等其他系统上运行,无需安装 Python。

详见 Intro to graphs (图的说明).

模块、层和模型

tf.Module是一个类,用于管理tf.Variable对象以及对它们进行操作的tf.function对象。 有了tf.Module类,才能支持下面两个重要特性:

  1. 可以用tf.train.Checkpoint保存和恢复变量的值。因为可以快速保存和恢复模型的状态,所以在训练期间很有用。

  2. 可以用tf.saved_model导入和导出tf.Variabletf.function图。这使得模型可以不依赖原来的 Python 程序独立运行。

下面是一个导出简单tf.Module对象的完整例子:

class MyModule(tf.Module): def __init__(self, value): self.weight = tf.Variable(value) @tf.function def multiply(self, x): return x * self.weight
mod = MyModule(3) mod.multiply(tf.constant([1, 2, 3]))

保存Module

save_path = './saved' tf.saved_model.save(mod, save_path)

保存的图独立于创建它的代码。您可以从 Python、其他语言绑定或TensorFlow Serving加载保存的图。还可以通过转换,让它在TensorFlow LiteTensorFlow JS上运行。

reloaded = tf.saved_model.load(save_path) reloaded.multiply(tf.constant([1, 2, 3]))

建立在tf.Module上的tf.keras.layers.Layer类和tf.keras.Model类,为构建、训练和保存模型提供了更多的功能和便利。下一节中将展示其中一部分。

详见 Intro to modules (模块介绍).

训练循环

现在用这些东西一起构建一个基本模型并从头开始训练。

首先,生成一些示例数据,这是一些围绕二次曲线的松散的点形成的云:

import matplotlib from matplotlib import pyplot as plt matplotlib.rcParams['figure.figsize'] = [9, 6]
x = tf.linspace(-2, 2, 201) x = tf.cast(x, tf.float32) def f(x): y = x**2 + 2*x - 5 return y y = f(x) + tf.random.normal(shape=[201]) plt.plot(x.numpy(), y.numpy(), '.', label='Data') plt.plot(x, f(x), label='Ground truth') plt.legend();

创建一个具有随机初始化权重和偏差的二次模型:

class Model(tf.Module): def __init__(self): # Randomly generate weight and bias terms rand_init = tf.random.uniform(shape=[3], minval=0., maxval=5., seed=22) # Initialize model parameters self.w_q = tf.Variable(rand_init[0]) self.w_l = tf.Variable(rand_init[1]) self.b = tf.Variable(rand_init[2]) @tf.function def __call__(self, x): # Quadratic Model : quadratic_weight * x^2 + linear_weight * x + bias return self.w_q * (x**2) + self.w_l * x + self.b

首先,在训练前观察您的模型的性能:

quad_model = Model()
def plot_preds(x, y, f, model, title): plt.figure() plt.plot(x, y, '.', label='Data') plt.plot(x, f(x), label='Ground truth') plt.plot(x, model(x), label='Predictions') plt.title(title) plt.legend()
plot_preds(x, y, f, quad_model, 'Before training')

现在,为您的模型定义损失:

鉴于此模型的作用是预测连续值,因此均方误差 (MSE) 是损失函数的不错选择。给定一个预测向量 y^\hat{y} 和一个真实目标向量 yy,MSE 被定义为预测值与基准值之间平方差的平均值。

MSE=1mi=1m(y^iyi)2MSE = \frac{1}{m}\sum_{i=1}^{m}(\hat{y}_i -y_i)^2

def mse_loss(y_pred, y): return tf.reduce_mean(tf.square(y_pred - y))

为模型编写一个基本训练循环。此循环将利用 MSE 损失函数及其相对于输入的梯度来迭代更新模型的参数。使用 mini-batch 进行训练可以提供内存效率和更快的收敛速度。tf.data.Dataset API 具有用于批处理和重排的实用函数。

batch_size = 32 dataset = tf.data.Dataset.from_tensor_slices((x, y)) dataset = dataset.shuffle(buffer_size=x.shape[0]).batch(batch_size)
# Set training parameters epochs = 100 learning_rate = 0.01 losses = [] # Format training loop for epoch in range(epochs): for x_batch, y_batch in dataset: with tf.GradientTape() as tape: batch_loss = mse_loss(quad_model(x_batch), y_batch) # Update parameters with respect to the gradient calculations grads = tape.gradient(batch_loss, quad_model.variables) for g,v in zip(grads, quad_model.variables): v.assign_sub(learning_rate*g) # Keep track of model loss per epoch loss = mse_loss(quad_model(x), y) losses.append(loss) if epoch % 10 == 0: print(f'Mean squared error for step {epoch}: {loss.numpy():0.3f}') # Plot model results print("\n") plt.plot(range(epochs), losses) plt.xlabel("Epoch") plt.ylabel("Mean Squared Error (MSE)") plt.title('MSE loss vs training iterations');

现在,观察模型在训练后的性能:

plot_preds(x, y, f, quad_model, 'After training')

成功了,但请记住,tf.keras 模块中提供了常见训练实用工具的实现。因此在您自己动手编写之前,请优先考虑使用现成的内容。首先,Model.compileModel.fit 方法为您实现了一个训练循环:

首先,使用 tf.keras.Sequential 在 Keras 中创建一个序贯模型。最简单的 Keras 层之一是密集层,可以使用 tf.keras.layers.Dense 进行实例化。密集层能够学习 Y=WX+b\mathrm{Y} = \mathrm{W}\mathrm{X} + \vec{b} 形式的多维线性关系。要学习 w1x2+w2x+bw_1x^2 + w_2x + b 形式的非线性方程,密集层的输入应当是一个以 x2x^2xx 为特征的数据矩阵。lambda 层 tf.keras.layers.Lambda 可用于执行这种堆叠转换。

new_model = tf.keras.Sequential([ tf.keras.layers.Lambda(lambda x: tf.stack([x, x**2], axis=1)), tf.keras.layers.Dense(units=1, kernel_initializer=tf.random.normal)])
new_model.compile( loss=tf.keras.losses.MSE, optimizer=tf.keras.optimizers.SGD(learning_rate=0.01)) history = new_model.fit(x, y, epochs=100, batch_size=32, verbose=0) new_model.save('./my_new_model')

训练后观察 Keras 模型的性能:

plt.plot(history.history['loss']) plt.xlabel('Epoch') plt.ylim([0, max(plt.ylim())]) plt.ylabel('Loss [Mean Squared Error]') plt.title('Keras training progress');
plot_preds(x, y, f, new_model, 'After Training: Keras')

请参阅基本训练循环Keras 指南,了解更多详细信息。