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 na TPU". Elas podem ser feitas na ordem abaixo 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 modo eficiente
Feedback
Se você encontrar algo de errado nesse codelab, informe-nos. O feedback pode ser enviado pela página de problemas do GitHub [link do feedback].
2. Introdução ao Google Colaboratory
Este laboratório usa o Google Collaboratory, e você não precisa configurar nada. O Colaboratory é uma plataforma de cadernos 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.
Selecionar um back-end de TPU
No menu do Colab, selecione Ambiente de execução > Alterar tipo de ambiente de execução e selecione TPU. Neste codelab, você usará uma TPU (Unidade de Processamento de Tensor) poderosa 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 de notebooks
Execute uma célula de cada vez clicando em uma célula e usando Shift-ENTER. Também é possível executar todo o notebook em Ambiente de execução > Executar tudo.
Índice
Todos os notebooks têm um sumário. Você pode abrir usando a seta preta à esquerda.
Células ocultas
Algumas células mostrarão apenas o título. Esse é um recurso específico do Colab. Você pode clicar duas vezes neles para ver o código, mas ele geralmente não é muito interessante. Normalmente, são funções de suporte ou visualização. Você ainda precisa executar essas células para que as funções internas sejam definidas.
Authentication
O Colab pode acessar seus buckets particulares do Google Cloud Storage desde que você faça a autenticação com uma conta autorizada. O snippet de código acima aciona um processo de autenticação.
3. [INFO] O que são as Unidades de Processamento de Tensor (TPUs)?
Resumindo
O código para treinar um modelo em TPU no Keras (e usar a GPU ou a 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 diversas tarefas, como renderização 3D, aprendizado profundo, simulações físicas etc. Por outro lado, as TPUs combinam um processador vetorial clássico com uma unidade de multiplicação de matriz dedicada e se destacam em qualquer tarefa em que as multiplicações de matrizes grandes dominam, como redes neurais.
Ilustração: uma camada de rede neural densa como uma multiplicação de matrizes, com um lote de oito imagens processadas pela rede neural de uma só vez. Execute a multiplicação de uma linha x coluna para verificar se ela está de fato 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 isso seja um pouco mais complicado ( explicação aqui, na seção 1).
O hardware
MXU e VPU
O núcleo da TPU v2 é composto de uma unidade de multiplicação de matriz (MXU) que executa multiplicações de matriz e uma Unidade de processamento vetorial (VPU) para todas as outras tarefas, como ativações, softmax etc. A VPU lida com cálculos de float32 e int32. O MXU, por outro lado, opera em um formato de ponto flutuante de precisão mista de 16 a 32 bits.
Ponto flutuante de precisão mista e bfloat16
O MXU calcula multiplicações de matrizes usando entradas bfloat16 e saídas float32. Acumulações intermediárias são realizadas com precisão de float32.
O treinamento de rede neural costuma ser resistente ao ruído introduzido por uma precisão de ponto flutuante reduzida. Há casos em que o ruído até ajuda a convergir o otimizador. A precisão de ponto flutuante de 16 bits tem sido usada tradicionalmente para acelerar cálculos, mas os formatos float16 e float32 têm intervalos muito diferentes. Reduzir a precisão de float32 para float16 geralmente resulta em fluxos excessivos e insuficientes. Existem soluções, mas é necessário um trabalho adicional para que o float16 funcione.
É por isso que o Google introduziu o formato bfloat16 em TPUs. bfloat16 é um float32 truncado com exatamente os mesmos bits e intervalo expoentes que float32. Isso, somado ao fato de que as TPUs computam multiplicações de matrizes em precisão mista com entradas bfloat16 e saídas float32, significa que, normalmente, nenhuma mudança no código é necessária para se beneficiar dos ganhos de desempenho com 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êmico" se refere às contrações cardíacas e ao fluxo sanguíneo, e aqui se refere 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 matriz (consulte a ilustração na parte de cima desta seção). Para uma multiplicação de matriz 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 "core" da GPU e executado em tantos "cores" disponíveis em paralelo para tentar calcular todos os valores da matriz resultante de uma só vez. Se a matriz resultante fosse 128 x 128 grande, seria necessário que 128 x 128=16 mil "núcleos" estivessem disponíveis, o que normalmente não é possível. As GPUs maiores têm cerca de 4.000 núcleos. Por outro lado, uma TPU usa o mínimo de hardware para as unidades de computação na MXU: apenas acumuladores de multiplicação bfloat16 x bfloat16 => float32
, nada mais. Elas são tão pequenas que uma TPU pode implementar 16 mil delas em uma MXU de 128 x 128 e processar essa multiplicação de matriz 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 cinza). As linhas verticais propagam os valores para cima. As linhas horizontais propagam somas parciais. O usuário deve verificar se, à medida que os dados fluem pela matriz, o resultado da multiplicação da matriz aparece no lado direito.
Além disso, enquanto os produtos pontuais são calculados em um MXU, as somas intermediárias simplesmente fluem entre as unidades de computação adjacentes. Eles não precisam ser armazenados e recuperados da/da memória ou mesmo de um arquivo de registro. O resultado final é que a arquitetura de matriz sistólico da TPU tem uma vantagem significativa de densidade e potência, além de uma vantagem de velocidade não desprezível em relação a uma GPU, ao calcular multiplicações de matriz.
Cloud TPU
Ao solicitar uma "Cloud TPU v2" no Google Cloud Platform, você recebe uma máquina virtual (VM) com uma placa de TPU conectada a PCI. A placa de TPU tem quatro chips de TPU de núcleo duplo. Cada núcleo de TPU tem uma unidade de processamento vetorial (VPU) e uma unidade de multiplicação de matrizes (MXU) de 128 x 128. Essa "Cloud TPU" geralmente é conectada pela rede à VM que a solicitou. O quadro completo fica assim:
Ilustração: sua VM com um acelerador "Cloud TPU" conectado à rede. O "Cloud TPU" é composto por uma VM com uma placa TPU conectada a PCI com quatro chips de TPU de núcleo duplo.
Pods TPU
Nos data centers do Google, as TPUs são conectadas a uma interconexão de computação de alto desempenho (HPC), 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 da TPU v3. Placas e racks de TPU conectados por interconexão de HPC.
Durante o treinamento, os gradientes são trocados entre núcleos de TPU usando o algoritmo de redução total. Confira uma boa explicação sobre a redução total. O modelo que está sendo treinado pode aproveitar o hardware com o treinamento em lotes grandes.
Ilustração: sincronização de gradientes durante o treinamento usando o algoritmo de redução total na rede HPC de malha toroidal 2D do Google TPU.
O software
Treinamento de tamanho de lote grande
O tamanho de lote ideal para TPUs é de 128 itens de dados por núcleo, mas o hardware já pode mostrar uma boa utilização com 8 itens de dados por núcleo. Lembre-se de que um Cloud TPU tem 8 núcleos.
Neste codelab, vamos usar a API Keras. No Keras, o lote especificado é o tamanho global de lote para toda a TPU. Seus lotes serão divididos automaticamente em 8 e executados nos 8 núcleos do TPU.
Para mais dicas sobre desempenho, consulte o Guia de desempenho da TPU. Para tamanhos de lote muito grandes, pode ser necessário um cuidado especial em alguns modelos. Consulte LARSOptimizer para mais detalhes.
Em segundo plano: XLA
Os programas do TensorFlow definem gráficos de computação. Ela não executa o código Python diretamente, e sim o gráfico de computação definido pelo programa do TensorFlow. Em segundo plano, um compilador chamado XLA (Acelerador de álgebra linear) transforma o gráfico de nós de computação do Tensorflow em código de máquina da TPU. Esse compilador também realiza muitas otimizações avançadas no código e no layout de memória. A compilação acontece automaticamente quando o trabalho é enviado para a TPU. Você não precisa incluir o XLA explicitamente na sua cadeia de compilação.
Ilustração: para executar 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 TPU.
Como usar TPUs no Keras
As TPUs são compatíveis com a API Keras a partir do Tensorflow 2.1. O suporte a Keras funciona em TPUs e pods da TPU. Confira um exemplo que funciona em TPU, GPU e CPU:
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 criados com o utilitário "gsutil 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 chameTPUClusterResolver
com 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 meio de um escopo. O modelo precisa ser definido dentro do scope() da estratégia.
- A função
tpu_model.fit
espera um objeto tf.data.Dataset para entrada no treinamento da TPU.
Tarefas comuns de portabilidade de TPU
- Embora haja muitas maneiras de carregar dados em um modelo do TensorFlow, para TPUs, o uso da API
tf.data.Dataset
é necessário. - As TPUs são muito rápidas, e a ingestão de dados geralmente se torna um gargalo durante a execução delas. Existem ferramentas que podem ser usadas para detectar gargalos de dados e outras dicas de desempenho no Guia de desempenho da TPU.
- Os números int8 ou int16 são tratados como int32. A TPU não tem hardware inteiro que opera em menos de 32 bits.
- Algumas operações do TensorFlow não são compatíveis. Confira a lista aqui. A boa notícia é que essa limitação se aplica apenas ao código de treinamento, ou seja, a passagem para frente e para trás pelo modelo. Ainda é possível usar todas as operações do TensorFlow no pipeline de entrada de dados, já que elas serão executadas na CPU.
tf.py_func
não é compatível com a TPU.
4. Como carregar dados
Vamos trabalhar com um conjunto de dados de fotos de flores. O objetivo é aprender a categorizar as flores em cinco tipos. O carregamento de dados é realizado 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 encontrar o rótulo "WORK REQUIRED".
Fun with tf.data.Dataset (playground).ipynb
Informações adicionais
Sobre o conjunto de dados "flowers"
O conjunto de dados é organizado em cinco pastas. Cada pasta contém flores de um tipo. As pastas são nomeadas 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 usar o tf.data.Dataset?
O Keras e o Tensorflow aceitam Datasets em todas as funções de treinamento e avaliação. Depois de carregar dados em um conjunto, a API oferece todas as funcionalidades comuns que são ú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 sobre tf.data.Dataset
Os dados geralmente vêm em vários arquivos, como imagens. É possível criar um conjunto de dados de nomes de arquivos chamando:
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. Você terá um conjunto de dados de tuplas, e elas serão retornadas quando você iterar. Os valores retornados são tensores do TensorFlow prontos para serem consumidos pelo modelo. Chame .numpy()
neles para ver 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ê verá que é possível carregar algo como 1 ou 2 imagens por segundo. Isso é muito lento! Os aceleradores de hardware que vamos usar no treinamento podem manter essa taxa muitas vezes. Vá para a próxima seção para ver como conseguiremos isso.
Solução
Este é o notebook da solução. Você pode usá-la 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
- 😀 Iterar por conjuntos de dados
Reserve um momento para rever esta lista de verificação em sua cabeça.
5. Carregamento rápido de dados
Os aceleradores de hardware da Unidade de Processamento de Tensor (TPU) que vamos usar neste laboratório são muito rápidos. O desafio muitas vezes é alimentá-los com dados rápido o suficiente para mantê-los ocupados. O Google Cloud Storage (GCS) é capaz de manter um throughput muito alto, mas, como em todos os sistemas de armazenamento em nuvem, a inicialização de uma conexão custa uma certa quantidade de rede. Portanto, não é ideal armazenar nossos dados como milhares de arquivos individuais. Vamos agrupar esses arquivos em um número menor e usar o poder do tf.data.Dataset para ler vários arquivos em paralelo.
Leitura
O código que carrega arquivos de imagem, os redimensiona para um tamanho comum e os armazena em 16 arquivos TFRecord está no notebook a seguir. Leia rapidamente. Não é necessário executá-la porque os dados formatados em TFRecord serão fornecidos corretamente para o restante do codelab.
Flower pictures to TFRecords.ipynb
Layout de dados ideal para a melhor taxa de transferência do GCS
Formato de arquivo TFRecord
O formato de arquivo preferencial do Tensorflow para armazenar dados é o TFRecord baseado em protobuf. Outros formatos de serialização também funcionam, mas você pode carregar um conjunto de dados de arquivos TFRecord diretamente 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, é recomendável usar o código mais complexo abaixo para ler vários arquivos TFRecord de uma só vez. Esse código vai ler de 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
É possível armazenar três tipos de dados em TFRecords: strings de bytes (lista de bytes), números inteiros de 64 bits e flutuantes de 32 bits. Eles são sempre armazenados como listas, um único elemento de dados será uma lista de tamanho 1. É possível usar as funções auxiliares a seguir para armazenar dados em TFRecords.
como 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))
gravar números inteiros
def _int_feature(list_of_ints): # int64
return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))
gravar flutuações
def _float_feature(list_of_floats): # float32
return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))
criar um TFRecord usando os auxiliares 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 do TFRecords, primeiro é preciso declarar o layout dos registros armazenados. Na declaração, você pode acessar qualquer campo nomeado como uma lista de tamanho fixo ou variável:
lendo no 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:
Como ler 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
Como 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. Depois de decodificar o TFRecord, é necessário realizar uma etapa adicional:
dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])
Também é possível ter campos opcionais no TFRecords. Se você especificar um valor padrão ao ler um campo, ele será retornado em vez de um erro se o campo estiver ausente.
tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional
O que vimos
- 🤔 Fragmentação de arquivos de dados para acesso rápido pelo GCS
- 😝 como escrever TFRecords. (Você já esqueceu a sintaxe? Sem problemas. Salve esta página como uma folha de dicas.
- 🤔 Como carregar um conjunto de dados de TFRecords usando o TFRecordDataset
Leia esta lista de verificação.
6. Parabéns!
Agora é possível alimentar uma TPU com dados. Prossiga para o próximo laboratório
- [ESTE LABORATÓRIO] Pipelines de dados de velocidade da 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
TPUs e GPUs estão disponíveis na AI Platform do Cloud:
- em VMs de aprendizado profundo
- Nos Notebooks do AI Platform
- Nos jobs do AI Platform Training
Finalmente, adoramos feedback. Informe se você encontrar algo errado neste laboratório ou se achar que ele precisa ser melhorado. O feedback pode ser enviado pela página de problemas do GitHub [link do feedback].
|