Noções básicas do TensorFlow

Veja no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

Este guia fornece uma visão geral rápida dos conceitos básicos do TensorFlow . Cada seção deste documento é uma visão geral de um tópico maior - você pode encontrar links para guias completos no final de cada seção.

O TensorFlow é uma plataforma de ponta a ponta para aprendizado de máquina. Ele suporta o seguinte:

  • Computação numérica baseada em matriz multidimensional (semelhante a NumPy .)
  • GPU e processamento distribuído
  • Diferenciação automática
  • Construção, treinamento e exportação de modelos
  • E mais

Tensores

O TensorFlow opera em matrizes ou tensores multidimensionais representados como objetos tf.Tensor . Aqui está um tensor bidimensional:

import tensorflow as tf

x = tf.constant([[1., 2., 3.],
                 [4., 5., 6.]])

print(x)
print(x.shape)
print(x.dtype)
tf.Tensor(
[[1. 2. 3.]
 [4. 5. 6.]], shape=(2, 3), dtype=float32)
(2, 3)
<dtype: 'float32'>

Os atributos mais importantes de um tf.Tensor são sua shape e dtype :

  • Tensor.shape : informa o tamanho do tensor ao longo de cada um de seus eixos.
  • Tensor.dtype : informa o tipo de todos os elementos no tensor.

O TensorFlow implementa operações matemáticas padrão em tensores, bem como muitas operações especializadas para aprendizado de máquina.

Por exemplo:

x + x
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ 2.,  4.,  6.],
       [ 8., 10., 12.]], dtype=float32)>
5 * x
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[ 5., 10., 15.],
       [20., 25., 30.]], dtype=float32)>
x @ tf.transpose(x)
<tf.Tensor: shape=(2, 2), dtype=float32, numpy=
array([[14., 32.],
       [32., 77.]], dtype=float32)>
tf.concat([x, x, x], axis=0)
<tf.Tensor: shape=(6, 3), dtype=float32, numpy=
array([[1., 2., 3.],
       [4., 5., 6.],
       [1., 2., 3.],
       [4., 5., 6.],
       [1., 2., 3.],
       [4., 5., 6.]], dtype=float32)>
tf.nn.softmax(x, axis=-1)
<tf.Tensor: shape=(2, 3), dtype=float32, numpy=
array([[0.09003057, 0.24472848, 0.6652409 ],
       [0.09003057, 0.24472848, 0.6652409 ]], dtype=float32)>
tf.reduce_sum(x)
<tf.Tensor: shape=(), dtype=float32, numpy=21.0>

A execução de grandes cálculos na CPU pode ser lenta. Quando configurado corretamente, o TensorFlow pode usar hardware acelerador, como GPUs, para executar operações muito rapidamente.

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

Consulte o guia Tensor para obter detalhes.

Variáveis

Objetos tf.Tensor normais são imutáveis. Para armazenar pesos de modelo (ou outro estado mutável) no TensorFlow, use um tf.Variable .

var = tf.Variable([0.0, 0.0, 0.0])
var.assign([1, 2, 3])
<tf.Variable 'UnreadVariable' shape=(3,) dtype=float32, numpy=array([1., 2., 3.], dtype=float32)>
var.assign_add([1, 1, 1])
<tf.Variable 'UnreadVariable' shape=(3,) dtype=float32, numpy=array([2., 3., 4.], dtype=float32)>

Consulte o guia Variáveis para obter detalhes.

Diferenciação automática

A descida de gradiente e os algoritmos relacionados são a base do aprendizado de máquina moderno.

Para habilitar isso, o TensorFlow implementa a diferenciação automática (autodiff), que usa cálculo para calcular gradientes. Normalmente, você usará isso para calcular o gradiente do erro ou perda de um modelo em relação a seus pesos.

x = tf.Variable(1.0)

def f(x):
  y = x**2 + 2*x - 5
  return y
f(x)
<tf.Tensor: shape=(), dtype=float32, numpy=-2.0>

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

A derivada de y é y' = f'(x) = (2*x + 2) = 4 . O TensorFlow pode calcular isso automaticamente:

with tf.GradientTape() as tape:
  y = f(x)

g_x = tape.gradient(y, x)  # g(x) = dy/dx

g_x
<tf.Tensor: shape=(), dtype=float32, numpy=4.0>

Este exemplo simplificado leva apenas a derivada em relação a um único escalar ( x ), mas o TensorFlow pode calcular o gradiente em relação a qualquer número de tensores não escalares simultaneamente.

Consulte o guia Autodiff para obter detalhes.

Gráficos e tf.function

Embora você possa usar o TensorFlow interativamente como qualquer biblioteca Python, o TensorFlow também fornece ferramentas para:

  • Otimização de desempenho : para acelerar o treinamento e a inferência.
  • Exportar : para que você possa salvar seu modelo quando terminar o treinamento.

Eles exigem que você use tf.function para separar seu código Pure-TensorFlow do Python.

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

A primeira vez que você executa o tf.function , embora ele seja executado em Python, ele captura um gráfico completo e otimizado representando os cálculos do TensorFlow feitos dentro da função.

x = tf.constant([1, 2, 3])
my_func(x)
Tracing.
<tf.Tensor: shape=(), dtype=int32, numpy=6>

Nas chamadas subsequentes, o TensorFlow executa apenas o gráfico otimizado, ignorando todas as etapas não relacionadas ao TensorFlow. Abaixo, observe que my_func não imprime rastreamento , pois print é uma função do Python, não uma função do TensorFlow.

x = tf.constant([10, 9, 8])
my_func(x)
<tf.Tensor: shape=(), dtype=int32, numpy=27>

Um gráfico pode não ser reutilizável para entradas com uma assinatura diferente ( shape e dtype ), portanto, um novo gráfico é gerado:

x = tf.constant([10.0, 9.1, 8.2], dtype=tf.float32)
my_func(x)
Tracing.
<tf.Tensor: shape=(), dtype=float32, numpy=27.3>

Esses gráficos capturados fornecem dois benefícios:

  • Em muitos casos, eles fornecem uma aceleração significativa na execução (embora não neste exemplo trivial).
  • Você pode exportar esses gráficos, usando tf.saved_model , para executar em outros sistemas como um servidor ou um dispositivo móvel , sem necessidade de instalação do Python.

Consulte Introdução aos gráficos para obter mais detalhes.

Módulos, camadas e modelos

tf.Module é uma classe para gerenciar seus objetos tf.Variable e os objetos tf.function que operam neles. A classe tf.Module é necessária para dar suporte a dois recursos significativos:

  1. Você pode salvar e restaurar os valores de suas variáveis ​​usando tf.train.Checkpoint . Isso é útil durante o treinamento, pois é rápido salvar e restaurar o estado de um modelo.
  2. Você pode importar e exportar os valores tf.Variable e os gráficos tf.function usando tf.saved_model . Isso permite que você execute seu modelo independentemente do programa Python que o criou.

Aqui está um exemplo completo de exportação de um objeto tf.Module simples:

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]))
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([3, 6, 9], dtype=int32)>

Salve o Module :

save_path = './saved'
tf.saved_model.save(mod, save_path)
INFO:tensorflow:Assets written to: ./saved/assets
2022-01-19 02:29:48.135588: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.

O SavedModel resultante é independente do código que o criou. Você pode carregar um SavedModel do Python, outras associações de linguagem ou TensorFlow Serving . Você também pode convertê-lo para ser executado com TensorFlow Lite ou TensorFlow JS .

reloaded = tf.saved_model.load(save_path)
reloaded.multiply(tf.constant([1, 2, 3]))
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([3, 6, 9], dtype=int32)>

As classes tf.keras.layers.Layer e tf.keras.Model construídas no tf.Module , fornecendo funcionalidades adicionais e métodos convenientes para construir, treinar e salvar modelos. Algumas delas são demonstradas na próxima seção.

Consulte Introdução aos módulos para obter detalhes.

Loops de treinamento

Agora junte tudo isso para construir um modelo básico e treiná-lo do zero.

Primeiro, crie alguns dados de exemplo. Isso gera uma nuvem de pontos que segue vagamente uma curva quadrática:

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();

png

Crie um modelo:

class Model(tf.keras.Model):
  def __init__(self, units):
    super().__init__()
    self.dense1 = tf.keras.layers.Dense(units=units,
                                        activation=tf.nn.relu,
                                        kernel_initializer=tf.random.normal,
                                        bias_initializer=tf.random.normal)
    self.dense2 = tf.keras.layers.Dense(1)

  def call(self, x, training=True):
    # For Keras layers/models, implement `call` instead of `__call__`.
    x = x[:, tf.newaxis]
    x = self.dense1(x)
    x = self.dense2(x)
    return tf.squeeze(x, axis=1)
model = Model(64)
plt.plot(x.numpy(), y.numpy(), '.', label='data')
plt.plot(x, f(x),  label='Ground truth')
plt.plot(x, model(x), label='Untrained predictions')
plt.title('Before training')
plt.legend();

png

Escreva um loop de treinamento básico:

variables = model.variables

optimizer = tf.optimizers.SGD(learning_rate=0.01)

for step in range(1000):
  with tf.GradientTape() as tape:
    prediction = model(x)
    error = (y-prediction)**2
    mean_error = tf.reduce_mean(error)
  gradient = tape.gradient(mean_error, variables)
  optimizer.apply_gradients(zip(gradient, variables))

  if step % 100 == 0:
    print(f'Mean squared error: {mean_error.numpy():0.3f}')
Mean squared error: 16.123
Mean squared error: 0.997
Mean squared error: 0.964
Mean squared error: 0.946
Mean squared error: 0.932
Mean squared error: 0.921
Mean squared error: 0.913
Mean squared error: 0.907
Mean squared error: 0.901
Mean squared error: 0.897
plt.plot(x.numpy(),y.numpy(), '.', label="data")
plt.plot(x, f(x),  label='Ground truth')
plt.plot(x, model(x), label='Trained predictions')
plt.title('After training')
plt.legend();

png

Isso está funcionando, mas lembre-se de que implementações de utilitários de treinamento comuns estão disponíveis no módulo tf.keras . Portanto, considere usá-los antes de escrever o seu próprio. Para começar, os métodos Model.compile e Model.fit implementam um loop de treinamento para você:

new_model = Model(64)
new_model.compile(
    loss=tf.keras.losses.MSE,
    optimizer=tf.optimizers.SGD(learning_rate=0.01))

history = new_model.fit(x, y,
                        epochs=100,
                        batch_size=32,
                        verbose=0)

model.save('./my_model')
INFO:tensorflow:Assets written to: ./my_model/assets
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');

png

Consulte Loops de treinamento básico e o guia Keras para obter mais detalhes.