1. Visão geral
As TPUs são muito rápidas. O fluxo de dados de treinamento precisa acompanhar a velocidade delas. Neste laboratório, você vai aprender a carregar dados do GCS com a API tf.data.Dataset para alimentar a TPU.
Este laboratório é a Parte 1 da série "Keras no TPU". Você pode fazer isso na ordem a seguir ou de forma independente.
- [ESTE LABORATÓRIO] Pipelines de dados com velocidade de TPU: tf.data.Dataset e TFRecords
- Seu primeiro modelo do Keras com aprendizado por transferência
- Redes neurais convolucionais com Keras e TPUs
- Convnets modernas, squeezenet, Xception, com Keras e TPUs

O que você vai aprender
- Usar a API tf.data.Dataset para carregar dados de treinamento
- Usar o formato TFRecord para carregar dados de treinamento do GCS de forma eficiente
Feedback
Se você notar algo errado neste codelab, informe-nos. O feedback pode ser enviado usando os problemas do GitHub [ link de feedback].
2. Início rápido do Google Colaboratory
Este laboratório usa o Google Colaboratory e não exige configuração da sua parte. O Colaboratory é uma plataforma de notebook on-line para fins educacionais. Ele oferece treinamento sem custo financeiro de CPU, GPU e TPU.

Abra este notebook de exemplo e execute algumas células para se familiarizar com o Colaboratory.
Selecione um back-end de TPU.

No menu do Colab, selecione Ambiente de execução > Alterar o tipo de ambiente de execução e escolha TPU. Neste codelab, você vai usar uma TPU (Unidade de Processamento de Tensor) avançada com suporte para treinamento acelerado por hardware. A conexão com o ambiente de execução acontece automaticamente na primeira execução, ou você pode usar o botão "Conectar" no canto superior direito.
Execução do notebook

Execute as células uma de cada vez clicando em uma delas e usando Shift + ENTER. Você também pode executar o notebook inteiro com Ambiente de execução > Executar tudo.
Índice

Todos os notebooks têm um sumário. É possível abrir usando a seta preta à esquerda.
Células ocultas

Algumas células vão mostrar apenas o título. Esse é um recurso específico do notebook do Colab. Clique duas vezes neles para ver o código, mas geralmente não é muito interessante. Normalmente, funções de suporte ou visualização. Ainda é necessário executar essas células para que as funções sejam definidas.
Authentication

O Colab pode acessar seus buckets privados do Google Cloud Storage, desde que você faça a autenticação com uma conta autorizada. O snippet de código acima vai acionar um processo de autenticação.
3. [INFO] O que são Unidades de Processamento de Tensor (TPUs)?
Em poucas palavras

O código para treinar um modelo em TPU no Keras (e usar GPU ou CPU se uma TPU não estiver disponível):
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
Hoje, vamos usar TPUs para criar e otimizar um classificador de flores em velocidades interativas (minutos por execução de treinamento).

Por que usar TPUs?
As GPUs modernas são organizadas em torno de "núcleos" programáveis, uma arquitetura muito flexível que permite lidar com várias tarefas, como renderização 3D, aprendizado profundo, simulações físicas etc. As TPUs, por outro lado, combinam um processador vetorial clássico com uma unidade de multiplicação de matrizes dedicada e se destacam em qualquer tarefa em que grandes multiplicações de matrizes predominam, como redes neurais.

Ilustração: uma camada densa de rede neural como uma multiplicação de matrizes, com um lote de oito imagens processadas pela rede neural de uma só vez. Faça uma multiplicação de linha por coluna para verificar se ela está fazendo uma soma ponderada de todos os valores de pixels de uma imagem. As camadas convolucionais também podem ser representadas como multiplicações de matrizes, embora seja um pouco mais complicado ( explicação aqui, na seção 1).
O hardware
MXU e VPU
Um núcleo de TPU v2 é composto por uma unidade de multiplicação de matrizes (MXU) que executa multiplicações de matrizes e uma unidade de processamento vetorial (VPU) para todas as outras tarefas, como ativações, softmax etc. A VPU processa cálculos float32 e int32. Já a MXU opera em um formato de ponto flutuante de precisão mista de 16 a 32 bits.

Ponto flutuante de precisão mista e bfloat16
A MXU calcula multiplicações de matrizes usando entradas bfloat16 e saídas float32. As acumulações intermediárias são realizadas com precisão float32.

O treinamento de redes neurais geralmente é resistente ao ruído introduzido por uma precisão de ponto flutuante reduzida. Há casos em que o ruído ajuda o otimizador a convergir. A precisão de ponto flutuante de 16 bits é usada tradicionalmente para acelerar cálculos, mas os formatos float16 e float32 têm intervalos muito diferentes. A redução da precisão de float32 para float16 geralmente resulta em estouros e subfluxos. Existem soluções, mas geralmente é necessário trabalho extra para fazer o float16 funcionar.
Por isso, o Google introduziu o formato bfloat16 nas TPUs. O bfloat16 é um float32 truncado com exatamente os mesmos bits de expoente e intervalo do float32. Isso, somado ao fato de que as TPUs calculam multiplicações de matriz em precisão mista com entradas bfloat16, mas saídas float32, significa que, normalmente, não são necessárias mudanças no código para aproveitar os ganhos de desempenho da precisão reduzida.
Matriz sistólica
A MXU implementa multiplicações de matrizes em hardware usando uma arquitetura chamada "matriz sistólica", em que os elementos de dados fluem por uma matriz de unidades de computação de hardware. Na medicina, "sistólica" se refere às contrações cardíacas e ao fluxo sanguíneo, e aqui ao fluxo de dados.
O elemento básico de uma multiplicação de matrizes é um produto escalar entre uma linha de uma matriz e uma coluna da outra (consulte a ilustração na parte de cima desta seção). Para uma multiplicação de matrizes Y=X*W, um elemento do resultado seria:
Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]
Em uma GPU, esse produto escalar seria programado em um "núcleo" da GPU e executado em quantos "núcleos" estiverem disponíveis em paralelo para tentar calcular todos os valores da matriz resultante de uma só vez. Se a matriz resultante for grande (128 x 128), serão necessários 128 x 128=16 mil "núcleos", o que geralmente não é possível. As maiores GPUs têm cerca de 4.000 núcleos. Uma TPU, por outro lado, usa o mínimo de hardware para as unidades de computação na MXU: apenas bfloat16 x bfloat16 => float32 acumuladores de multiplicação, nada mais. Elas são tão pequenas que uma TPU pode implementar 16 mil delas em uma MXU de 128x128 e processar essa multiplicação de matrizes de uma só vez.

Ilustração: a matriz sistólica da MXU. Os elementos de computação são acumuladores de multiplicação. Os valores de uma matriz são carregados na matriz (pontos vermelhos). Os valores da outra matriz fluem pela matriz (pontos cinzas). As linhas verticais propagam os valores para cima. As linhas horizontais propagam somas parciais. O usuário precisa verificar se, à medida que o fluxo de dados passa pela matriz, o resultado da multiplicação de matrizes sai do lado direito.
Além disso, enquanto os produtos escalares são calculados em uma MXU, as somas intermediárias simplesmente fluem entre unidades de computação adjacentes. Não é necessário armazená-los e recuperá-los da memória ou até mesmo de um arquivo de registro. O resultado final é que a arquitetura de matriz sistólica da TPU tem uma vantagem significativa de densidade e energia, além de uma vantagem de velocidade não insignificante em relação a uma GPU, ao calcular multiplicações de matrizes.
Cloud TPU
Ao solicitar um Cloud TPU v2 no Google Cloud Platform, você recebe uma máquina virtual (VM) com uma placa de TPU conectada por PCI. A placa de TPU tem quatro chips de TPU de núcleo duplo. Cada núcleo de TPU tem uma VPU (unidade de processamento vetorial) e uma MXU (unidade de multiplicação de matrizes) de 128x128. Essa "Cloud TPU" geralmente é conectada pela rede à VM que a solicitou. Então, o panorama completo é este:

Ilustração: sua VM com um acelerador "Cloud TPU" conectado à rede. "O Cloud TPU" em si é feito de uma VM com uma placa de TPU conectada a PCI com quatro chips de TPU de núcleo duplo.
Pods de TPU
Nos data centers do Google, as TPUs são conectadas a uma interconexão de computação de alto desempenho (HPC, na sigla em inglês), o que pode fazê-las parecer um acelerador muito grande. O Google os chama de pods, e eles podem abranger até 512 núcleos de TPU v2 ou 2.048 núcleos de TPU v3.

Ilustração: um pod de TPU v3. Placas e racks de TPU conectados por interconexão de HPC.
Durante o treinamento, os gradientes são trocados entre os núcleos da TPU usando o algoritmo de redução total ( boa explicação da redução total aqui). O modelo em treinamento pode aproveitar o hardware treinando com tamanhos de lote grandes.

Ilustração: sincronização de gradientes durante o treinamento usando o algoritmo all-reduce na rede HPC de malha toroidal 2D da TPU do Google.
O software
Treinamento com tamanho de lote grande
O tamanho do lote ideal para TPUs é de 128 itens de dados por núcleo de TPU, mas o hardware já pode mostrar boa utilização com 8 itens de dados por núcleo de TPU. Uma Cloud TPU tem oito núcleos.
Neste codelab, vamos usar a API Keras. No Keras, o lote especificado é o tamanho do lote global para toda a TPU. Seus lotes serão divididos automaticamente em 8 e executados nos 8 núcleos da TPU.

Para mais dicas de performance, consulte o Guia de performance de TPU. Para tamanhos de lote muito grandes, alguns modelos podem precisar de cuidados especiais. Consulte LARSOptimizer para mais detalhes.
Funcionamento interno: XLA
Os programas do TensorFlow definem gráficos de computação. A TPU não executa o código Python diretamente, mas sim o gráfico de computação definido pelo programa do TensorFlow. Nos bastidores, um compilador chamado XLA (compilador de álgebra linear acelerada) transforma o gráfico do Tensorflow de nós de computação em código de máquina da TPU. Esse compilador também realiza muitas otimizações avançadas no seu código e no layout da memória. A compilação acontece automaticamente à medida que o trabalho é enviado para a TPU. Não é necessário incluir o XLA explicitamente na sua cadeia de build.

Ilustração: para ser executado na TPU, o gráfico de computação definido pelo programa do TensorFlow é primeiro traduzido para uma representação do XLA (compilador de álgebra linear acelerada) e depois compilado pelo XLA em código de máquina da TPU.
Como usar TPUs no Keras
As TPUs são compatíveis com a API Keras desde o TensorFlow 2.1. O suporte do Keras funciona em TPUs e pods de TPU. Confira um exemplo que funciona em TPUs, GPUs e CPUs:
try: # detect TPUs
tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines
# use TPUStrategy scope to define model
with strategy.scope():
model = tf.keras.Sequential( ... )
model.compile( ... )
# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)
Neste snippet de código:
TPUClusterResolver().connect()encontra a TPU na rede. Ele funciona sem parâmetros na maioria dos sistemas do Google Cloud (jobs do AI Platform, Colaboratory, Kubeflow, VMs de aprendizado profundo criadas com o utilitário "ctpu up"). Esses sistemas sabem onde está a TPU graças a uma variável de ambiente TPU_NAME. Se você criar uma TPU manualmente, defina a variável de ambiente TPU_NAME na VM em que ela está sendo usada ou chameTPUClusterResolvercom parâmetros explícitos:TPUClusterResolver(tp_uname, zone, project)TPUStrategyé a parte que implementa a distribuição e o algoritmo de sincronização de gradiente "all-reduce".- A estratégia é aplicada por um escopo. O modelo precisa ser definido no escopo da estratégia().
- A função
tpu_model.fitespera um objeto tf.data.Dataset como entrada para treinamento de TPU.
Tarefas comuns de portabilidade de TPU
- Embora haja muitas maneiras de carregar dados em um modelo do TensorFlow, para TPUs, é necessário usar a API
tf.data.Dataset. - As TPUs são muito rápidas, e a ingestão de dados geralmente se torna o gargalo ao executar nelas. Há ferramentas que podem ser usadas para detectar gargalos de dados e outras dicas de desempenho no Guia de desempenho da TPU.
- Números int8 ou int16 são tratados como int32. A TPU não tem hardware de números inteiros operando em menos de 32 bits.
- Algumas operações do TensorFlow não são compatíveis. A lista está aqui. A boa notícia é que essa limitação se aplica apenas ao código de treinamento, ou seja, a passagem direta e indireta pelo modelo. Você ainda pode usar todas as operações do TensorFlow no pipeline de entrada de dados, já que ele será executado na CPU.
tf.py_funcnão é compatível com TPU.
4. Como carregar dados

Vamos trabalhar com um conjunto de dados de fotos de flores. O objetivo é aprender a categorizá-las em cinco tipos de flores. O carregamento de dados é feito usando a API tf.data.Dataset. Primeiro, vamos conhecer a API.
Prático
Abra o notebook a seguir, execute as células (Shift-ENTER) e siga as instruções sempre que vir o rótulo "TRABALHO NECESSÁRIO".
Fun with tf.data.Dataset (playground).ipynb
Informações adicionais
Sobre o conjunto de dados "flores"
O conjunto de dados está organizado em cinco pastas. Cada pasta contém flores de um tipo. As pastas são chamadas de girassóis, margaridas, dentes-de-leão, tulipas e rosas. Os dados são hospedados em um bucket público no Google Cloud Storage. Trecho:
gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg
Por que tf.data.Dataset?
O Keras e o TensorFlow aceitam conjuntos de dados em todas as funções de treinamento e avaliação. Depois de carregar dados em um conjunto de dados, a API oferece todas as funcionalidades comuns úteis para dados de treinamento de rede neural:
dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training
Confira dicas de performance e práticas recomendadas para conjuntos de dados neste artigo. A documentação de referência está aqui.
Noções básicas do tf.data.Dataset
Os dados geralmente vêm em vários arquivos, aqui imagens. Para criar um conjunto de dados de nomes de arquivos, chame:
filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.
Em seguida, você "mapeia" uma função para cada nome de arquivo, que normalmente carrega e decodifica o arquivo em dados reais na memória:
def decode_jpeg(filename):
bits = tf.io.read_file(filename)
image = tf.io.decode_jpeg(bits)
return image
image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)
Para iterar em um conjunto de dados:
for data in my_dataset:
print(data)
Conjuntos de dados de tuplas
No aprendizado supervisionado, um conjunto de dados de treinamento normalmente é composto por pares de dados de treinamento e respostas corretas. Para permitir isso, a função de decodificação pode retornar tuplas. Assim, você terá um conjunto de dados de tuplas, que serão retornadas quando você iterar nele. Os valores retornados são tensores do TensorFlow prontos para serem usados pelo seu modelo. É possível chamar .numpy() neles para conferir os valores brutos:
def decode_jpeg_and_label(filename):
bits = tf.read_file(filename)
image = tf.io.decode_jpeg(bits)
label = ... # extract flower name from folder name
return image, label
image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs
for image, label in dataset:
print(image.numpy().shape, label.numpy())
Conclusão:carregar imagens uma por uma é lento!
Ao iterar nesse conjunto de dados, você vai perceber que é possível carregar algo como uma ou duas imagens por segundo. Isso é muito lento! Os aceleradores de hardware que vamos usar para treinamento podem manter muitas vezes essa taxa. Consulte a próxima seção para saber como vamos fazer isso.
Solução
Confira o notebook de solução. Use se tiver dificuldades.
Fun with tf.data.Dataset (solution).ipynb
O que vimos
- 🤔 tf.data.Dataset.list_files
- 🤔 tf.data.Dataset.map
- 🤔 Conjuntos de dados de tuplas
- 😀 iterando por conjuntos de dados
Confira esta lista de verificação.
5. Carregar dados rapidamente
Os aceleradores de hardware da Unidade de Processamento de Tensor (TPU) que vamos usar neste laboratório são muito rápidos. O desafio é fornecer dados com rapidez suficiente para mantê-los ocupados. O Google Cloud Storage (GCS) é capaz de manter uma alta capacidade de processamento, mas, como em todos os sistemas de armazenamento em nuvem, iniciar uma conexão custa alguma troca de dados de rede. Portanto, não é ideal ter nossos dados armazenados como milhares de arquivos individuais. Vamos agrupar em lotes um número menor de arquivos e usar o poder do tf.data.Dataset para ler de vários arquivos em paralelo.
Read-through
O código que carrega arquivos de imagem, redimensiona para um tamanho comum e os armazena em 16 arquivos TFRecord está no notebook a seguir. Leia rapidamente. Não é necessário executar esse comando, já que dados formatados corretamente em TFRecord serão fornecidos para o restante do codelab.
Flower pictures to TFRecords.ipynb
Layout de dados ideal para uma capacidade de processamento ideal do GCS
O formato de arquivo TFRecord
O formato de arquivo preferido do TensorFlow para armazenar dados é o TFRecord baseado em protobuf. Outros formatos de serialização também funcionam, mas é possível carregar um conjunto de dados diretamente de arquivos TFRecord escrevendo:
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
Para um desempenho ideal, recomendamos usar o código mais complexo a seguir para ler vários arquivos TFRecord de uma só vez. Esse código vai ler N arquivos em paralelo e ignorar a ordem dos dados em favor da velocidade de leitura.
AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False
filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below
Folha de referência do TFRecord
Três tipos de dados podem ser armazenados em TFRecords: strings de bytes (lista de bytes), inteiros de 64 bits e pontos flutuantes de 32 bits. Eles são sempre armazenados como listas. Um único elemento de dados será uma lista de tamanho 1. Você pode usar as seguintes funções auxiliares para armazenar dados em TFRecords.
gravar strings de bytes
# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))
escrever números inteiros
def _int_feature(list_of_ints): # int64
return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))
gravar números de ponto flutuante
def _float_feature(list_of_floats): # float32
return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))
gravar um TFRecord usando os helpers acima
# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
feature = {
"image": _bytestring_feature([my_img_bytes]), # one image in the list
"class": _int_feature([my_class]), # one class in the list
"size": _int_feature([my_height, my_width]), # fixed length (2) list of ints
"float_data": _float_feature(my_floats) # variable length list of floats
}
tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
out_file.write(tf_record.SerializeToString())
Para ler dados de TFRecords, primeiro declare o layout dos registros armazenados. Na declaração, é possível acessar qualquer campo nomeado como uma lista de comprimento fixo ou variável:
leitura de TFRecords
def read_tfrecord(data):
features = {
# tf.string = byte string (not text string)
"image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
"class": tf.io.FixedLenFeature([], tf.int64), # shape [] means scalar, i.e. a single item
"size": tf.io.FixedLenFeature([2], tf.int64), # two integers
"float_data": tf.io.VarLenFeature(tf.float32) # a variable number of floats
}
# decode the TFRecord
tf_record = tf.io.parse_single_example(data, features)
# FixedLenFeature fields are now ready to use
sz = tf_record['size']
# Typical code for decoding compressed images
image = tf.io.decode_jpeg(tf_record['image'], channels=3)
# VarLenFeature fields require additional sparse.to_dense decoding
float_data = tf.sparse.to_dense(tf_record['float_data'])
return image, sz, float_data
# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)
Snippets de código úteis:
leitura de elementos de dados únicos
tf.io.FixedLenFeature([], tf.string) # for one byte string
tf.io.FixedLenFeature([], tf.int64) # for one int
tf.io.FixedLenFeature([], tf.float32) # for one float
ler listas de elementos de tamanho fixo
tf.io.FixedLenFeature([N], tf.string) # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64) # list of N ints
tf.io.FixedLenFeature([N], tf.float32) # list of N floats
ler um número variável de itens de dados
tf.io.VarLenFeature(tf.string) # list of byte strings
tf.io.VarLenFeature(tf.int64) # list of ints
tf.io.VarLenFeature(tf.float32) # list of floats
Um VarLenFeature retorna um vetor esparso, e uma etapa adicional é necessária após a decodificação do TFRecord:
dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])
Também é possível ter campos opcionais em TFRecords. Se você especificar um valor padrão ao ler um campo, esse valor será retornado em vez de um erro se o campo estiver faltando.
tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional
O que vimos
- 🤔 Fragmentar arquivos de dados para acesso rápido do GCS
- 😓 como escrever TFRecords. (Já se esqueceu da sintaxe? Tudo bem, adicione esta página aos favoritos como uma folha de dicas)
- 🤔 carregando um conjunto de dados de TFRecords usando TFRecordDataset
Confira esta lista de verificação.
6. Parabéns!
Agora é possível alimentar uma TPU com dados. Continue para o próximo laboratório
- [ESTE LABORATÓRIO] Pipelines de dados com velocidade de TPU: tf.data.Dataset e TFRecords
- Seu primeiro modelo do Keras com aprendizado por transferência
- Redes neurais convolucionais com Keras e TPUs
- Convnets modernas, squeezenet, Xception, com Keras e TPUs
TPUs na prática
As TPUs e GPUs estão disponíveis no AI Platform do Google Cloud:
- Em VMs de aprendizado profundo
- Em AI Platform Notebooks
- Nos jobs do AI Platform Training
Por fim, adoramos receber feedback. Informe se você notar algo errado neste laboratório ou se achar que ele pode ser melhorado. O feedback pode ser enviado usando os problemas do GitHub [ link de feedback].

|
|

