Path: blob/master/site/pt-br/guide/keras/preprocessing_layers.ipynb
25118 views
Copyright 2020 The TensorFlow Authors.
Trabalhando com camadas de pré-processamento
Pré-processamento com o Keras
A API de camadas de pré-processamento do Keras permite que desenvolvedores criem pipelines de processamento de entrada nativos do Keras. Esses pipelines de processamento de entrada podem ser usados como código de pré-processamento independente em outros workflows (que não usam Keras), combinados diretamente com modelos Keras e exportados como parte de um Keras SavedModel.
Com as camadas de pré-processamento do Keras, você pode construir e exportar modelos que são realmente modelos de ponta a ponta: modelos que aceitam imagens brutas ou dados estruturados brutos como entrada; modelos que lidam com normalização de recursos ou indexação de valores de recursos por conta própria.
Pré-processamentos disponíveis
Pré-processamento de texto
tf.keras.layers.TextVectorization
: transforma strings brutas em uma representação codificada que pode ser lida por uma camadaEmbedding
ou camadaDense
.
Pré-processamento de recursos numéricos
tf.keras.layers.Normalization
: executa uma normalização dos recursos de entrada.tf.keras.layers.Discretization
: transforma recursos numéricos contínuos em recursos categóricos inteiros.
Pré-processamento de recursos categóricos
tf.keras.layers.CategoryEncoding
: transforma recursos categóricos inteiros em representações one-hot, multi-hot ou contagens densas.tf.keras.layers.Hashing
: realiza hashing de recursos categóricos, também conhecido como "truque de hash".tf.keras.layers.StringLookup
: transforma valores categóricos de string em uma representação codificada que pode ser lida por uma camadaEmbedding
ou camadaDense
.tf.keras.layers.IntegerLookup
: transforma valores categóricos inteiros em uma representação codificada que pode ser lida por uma camadaEmbedding
ou camadaDense
.
Pré-processamento de imagens
Estas camadas servem para padronizar as entradas de um modelo de imagem.
tf.keras.layers.Resizing
: redimensiona um lote de imagens para um tamanho-alvo.tf.keras.layers.Rescaling
: redimensiona e desloca os valores de um lote de imagem (por exemplo, das entradas no intervalo[0, 255]
para entradas no intervalo[0, 1]
.tf.keras.layers.CenterCrop
: retorna um corte central de um lote de imagens.
Ampliação de dados de imagem
Essas camadas aplicam transformações de ampliação aleatória a um lote de imagens. Elas só são ativas durante o treinamento.
tf.keras.layers.RandomCrop
tf.keras.layers.RandomFlip
tf.keras.layers.RandomTranslation
tf.keras.layers.RandomRotation
tf.keras.layers.RandomZoom
tf.keras.layers.RandomHeight
tf.keras.layers.RandomWidth
tf.keras.layers.RandomContrast
O método adapt()
Algumas camadas de pré-processamento têm um estado interno que pode ser computado com base numa amostra dos dados de treinamento. A lista de camadas de pré-processamento stateful é:
TextVectorization
: mantém um mapeamento entre tokens de string e índices inteirosStringLookup
eIntegerLookup
: mantêm um mapeamento entre valores de entrada e índices inteiros.Normalization
: mantém a média e o desvio padrão dos recursos.Discretization
: mantém informações sobre limites de buckets de valores.
Crucialmente, essas camadas não são treináveis. Seu estado não é definido durante o treinamento; ele precisa ser definido antes do treinamento, ou inicializados a partir de uma constante pré-computada ou "adaptando-os" aos dados.
Você define o estado de uma camada de pré-processamento expondo-a a dados de treinamento através do método adapt()
:
O método adapt()
usa um array Numpy ou um objeto tf.data.Dataset
. No caso de StringLookup
e TextVectorization
, você também pode passar uma lista de strings:
Além disso, as camadas adaptáveis sempre apresentam uma alternativa para definir diretamente o estado via argumentos do construtor ou atribuição de peso. Se os valores de estado pretendidos forem conhecidos no momento da construção da camada ou forem calculados fora da chamada adapt()
, eles poderão ser definidos sem depender da computação interna da camada. Por exemplo, se já existirem arquivos de vocabulário externos para as camadas TextVectorization
, StringLookup
ou IntegerLookup
, eles podem ser carregados diretamente nas tabelas de pesquisa passando um caminho para o arquivo de vocabulário nos argumentos do construtor da camada.
Aqui está um exemplo onde instanciamos uma camada StringLookup
com vocabulário pré-computado:
Pré-processamento de dados antes do modelo ou dentro do modelo
Há duas maneiras de usar camadas de pré-processamento:
Opção 1: Torná-las parte do modelo, assim:
Com esta opção, o pré-processamento acontecerá no dispositivo, de forma sincronizada com o restante da execução do modelo, o que significa que ele se beneficiará da aceleração da GPU. Se você estiver treinando em GPU, esta é a melhor opção para a camada Normalization
e para todas as camadas de pré-processamento de imagem e ampliação de dados.
Opção 2: aplicá-las ao seu tf.data.Dataset
, para obter um dataset que gere lotes de dados pré-processados, como este:
Com esta opção, seu pré-processamento acontecerá na CPU, de forma assíncrona, e será armazenado em buffer antes de entrar no modelo. Além disso, se você chamar dataset.prefetch(tf.data.AUTOTUNE)
em seu dataset, o pré-processamento acontecerá de forma eficiente em paralelo com o treinamento:
Esta é a melhor alternativa para TextVectorization
e todas as camadas de pré-processamento de dados estruturados. Também pode ser uma boa opção se você estiver treinando na CPU e usa camadas de pré-processamento de imagem.
Ao executar em TPU, você sempre deve colocar as camadas de pré-processamento no pipeline tf.data
(com exceção de Normalization
e Rescaling
, que funcionam bem em TPU e são frequentemente usadas porque a primeira camada é um modelo de imagem).
Vantagens de fazer o pré-processamento dentro do modelo na hora da inferência
Mesmo que você escolha a opção 2, poderá desejar exportar posteriormente um modelo de ponta a ponta, de inferência apenas, que incluirá as camadas de pré-processamento. A principal vantagem de se fazer isso é que torna seu modelo portátil e ajuda a reduzir o desvio de treinamento/serviço.
Quando todo o pré-processamento de dados faz parte do modelo, outras pessoas podem carregar e usar seu modelo sem precisar saber como cada recurso deve ser codificado e normalizado. Seu modelo de inferência será capaz de processar imagens brutas ou dados estruturados brutos e não exigirá que os usuários do modelo estejam cientes dos detalhes de, por exemplo, o esquema de tokenização usado para texto, o esquema de indexação usado para recursos categóricos, se os valores de pixel da imagem são normalizados para [-1, +1]
ou para [0, 1]
, etc. Isto é muito poderoso se você estiver exportando seu modelo para outro ambiente de execução, como TensorFlow.js: você não precisará reimplementar seu pipeline de pré-processamento em JavaScript.
Se você inicialmente colocar suas camadas de pré-processamento no seu pipeline tf.data
, poderá exportar um modelo de inferência que empacote o pré-processamento. Basta instanciar um novo modelo que encadeia suas camadas de pré-processamento e seu modelo de treinamento:
Receitas rápidas
Ampliação de dados de imagem
Observe que as camadas de ampliação de dados de imagem são ativas apenas durante o treinamento (semelhante à camada Dropout
).
Você pode ver uma configuração semelhante em ação no exemplo classificação de imagem do zero.
Normalizando recursos numéricos
Codificando recursos categóricos de string via one-hot encoding
Observe que, aqui, o índice 0 é reservado para valores fora do vocabulário (valores que não foram vistos durante adapt()
).
Você pode ver o StringLookup
em ação no exemplo classificação de dados estruturados do zero.
Codificando recursos categóricos inteiros via one-hot encoding
Observe que o índice 0 é reservado para valores ausentes (que você deve especificar como o valor 0) e o índice 1 é reservado para valores fora do vocabulário (valores que não foram vistos durante adapt()
). Isto pode ser configurado com os argumentos mask_token
e oov_token
do construtor IntegerLookup
.
Você pode ver o IntegerLookup
em ação no exemplo classificação de dados estruturados do zero.
Aplicando o truque de hash a um recurso categórico inteiro
Se você tiver um recurso categórico que pode assumir muitos valores diferentes (na ordem de 10e3 ou superior), onde cada valor aparece apenas algumas vezes nos dados, torna-se impraticável e ineficaz indexar e fazer one-hot encoding dos valores do recurso. Em vez disso, pode ser uma boa ideia aplicar o "truque de hash": fazer hash dos valores para um vetor de tamanho fixo. Isto mantém o tamanho do espaço de recurso gerenciável e remove a necessidade de indexação explícita.
Codificando texto como uma sequência de índices de token
É assim que você deve pré-processar o texto a ser passado para uma camada Embedding
.
Você pode ver a camada TextVectorization
em ação, combinada com um modo Embedding
, no exemplo classificação de texto do zero.
Observe que, ao treinar tal modelo, para melhor desempenho, você deve sempre usar a camada TextVectorization
como parte do pipeline de entrada.
Codificando texto como uma matriz densa de ngrams com multi-hot encoding
É assim que você deve pré-processar o texto a ser passado para uma camada Dense
.
Codificando texto como uma matriz densa de ngrams com ponderação TF-IDF
Esta é uma forma alternativa de pré-processar o texto antes de passá-lo para uma camada Dense
.
Detalhes importantes
Trabalhando com camadas de pesquisa com vocabulários muito grandes
Você talvez se encontre trabalhando com um vocabulário muito grande numa TextVectorization
, numa camada StringLookup
ou numa camada IntegerLookup
. Normalmente, um vocabulário maior que 500 MB já seria considerado "muito grande".
Em tais casos, para melhor desempenho, evite usar adapt()
. Em vez disso, pré-compute seu vocabulário com antecedência (você pode usar o Apache Beam ou o TF Transform para isso) e armazene-o em um arquivo. Em seguida, carregue o vocabulário na camada no momento da construção, passando o caminho do arquivo como o argumento vocabulary
.
Usando camadas de pesquisa em um pod de TPU ou com ParameterServerStrategy
.
Há um bug importante que causa a degradação do desempenho ao usar uma camada TextVectorization
, StringLookup
ou IntegerLookup
durante o treinamento em um pod de TPU ou em várias máquinas via ParameterServerStrategy
. Isso está agendado para ser corrigido no TensorFlow 2.7.