Noções básicas de personalização: tensores e operações

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

Este é um tutorial introdutório do TensorFlow que mostra como:

  • Importe o pacote necessário
  • Criar e usar tensores
  • Usar aceleração de GPU
  • Demonstrar tf.data.Dataset

Importar TensorFlow

Para começar, importe o módulo tensorflow . A partir do TensorFlow 2, a execução antecipada é ativada por padrão. Isso permite um front-end mais interativo para o TensorFlow, cujos detalhes discutiremos muito mais tarde.

import tensorflow as tf

Tensores

Um tensor é uma matriz multidimensional. Semelhante aos objetos NumPy ndarray , os objetos tf.Tensor têm um tipo de dados e uma forma. Além disso, tf.Tensor s pode residir na memória do acelerador (como uma GPU). O TensorFlow oferece uma rica biblioteca de operações ( tf.add , tf.matmul , tf.linalg.inv etc.) que consomem e produzem tf.Tensor s. Essas operações convertem automaticamente os tipos nativos do Python, por exemplo:

print(tf.add(1, 2))
print(tf.add([1, 2], [3, 4]))
print(tf.square(5))
print(tf.reduce_sum([1, 2, 3]))

# Operator overloading is also supported
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)

Cada tf.Tensor tem uma forma e um tipo de dados:

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'>

As diferenças mais óbvias entre matrizes NumPy e tf.Tensor s são:

  1. Os tensores podem ser apoiados pela memória do acelerador (como GPU, TPU).
  2. Os tensores são imutáveis.

Compatibilidade NumPy

Converter entre um TensorFlow tf.Tensor um NumPy ndarray é fácil:

  • As operações do TensorFlow convertem automaticamente ndarrays NumPy em tensores.
  • As operações NumPy convertem automaticamente Tensores em ndarrays NumPy.

Os tensores são explicitamente convertidos em ndarrays NumPy usando seu método .numpy() . Essas conversões geralmente são baratas, pois o array e o tf.Tensor compartilham a representação de memória subjacente, se possível. No entanto, compartilhar a representação subjacente nem sempre é possível, pois o tf.Tensor pode ser hospedado na memória da GPU, enquanto os arrays NumPy são sempre suportados pela memória do host, e a conversão envolve uma cópia da GPU para a memória do host.

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.]]

Aceleração da GPU

Muitas operações do TensorFlow são aceleradas usando a GPU para computação. Sem anotações, o TensorFlow decide automaticamente se deve usar a GPU ou a CPU para uma operação, copiando o tensor entre a memória da CPU e da GPU, se necessário. Tensores produzidos por uma operação são normalmente apoiados pela memória do dispositivo no qual a operação foi executada, por exemplo:

x = tf.random.uniform([3, 3])

print("Is there a GPU available: "),
print(tf.config.list_physical_devices("GPU"))

print("Is the Tensor on GPU #0:  "),
print(x.device.endswith('GPU:0'))
Is there a GPU available: 
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
Is the Tensor on GPU #0:  
True

Nomes de dispositivos

A propriedade Tensor.device fornece um nome de string totalmente qualificado do dispositivo que hospeda o conteúdo do tensor. Esse nome codifica muitos detalhes, como um identificador do endereço de rede do host no qual esse programa está sendo executado e o dispositivo nesse host. Isso é necessário para a execução distribuída de um programa TensorFlow. A string termina com GPU:<N> se o tensor for colocado na N -th GPU no host.

Posicionamento explícito do dispositivo

No TensorFlow, o posicionamento refere-se a como as operações individuais são atribuídas (colocadas em) um dispositivo para execução. Conforme mencionado, quando não há orientação explícita fornecida, o TensorFlow decide automaticamente qual dispositivo executará uma operação e copia tensores para esse dispositivo, se necessário. No entanto, as operações do TensorFlow podem ser colocadas explicitamente em dispositivos específicos usando o gerenciador de contexto tf.device , por exemplo:

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.config.list_physical_devices("GPU"):
  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: 91.47ms
On GPU:
10 loops: 388.16ms

Conjuntos de dados

Esta seção usa a API tf.data.Dataset para criar um pipeline para alimentar dados em seu modelo. A API tf.data.Dataset é usada para criar pipelines de entrada complexos e de alto desempenho a partir de peças simples e reutilizáveis ​​que alimentarão os loops de treinamento ou avaliação do seu modelo.

Criar um conjunto de Dataset de origem

Crie um conjunto de dados de origem usando uma das funções de fábrica como Dataset.from_tensors , Dataset.from_tensor_slices ou usando objetos que lêem arquivos como TextLineDataset ou TFRecordDataset . Consulte o guia do conjunto de dados do TensorFlow para obter mais informações.

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)

Aplicar transformações

Use as funções de transformação como map , batch e shuffle para aplicar transformações aos registros do conjunto de dados.

ds_tensors = ds_tensors.map(tf.square).shuffle(2).batch(2)

ds_file = ds_file.batch(2)

Iterar

Os objetos tf.data.Dataset suportam iteração para fazer um loop nos registros:

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([16  4], shape=(2,), dtype=int32)
tf.Tensor([25 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)