De Sara Robinson, Developer Advocate

Vemos com frequência o aprendizado por transferência aplicado a modelos de visão computacional, mas será que funcionaria também para classificação de texto? Apresentamos o TensorFlow Hub, uma biblioteca para aprimorar modelos de TF com aprendizado por transferência. O aprendizado por transferência é o processo de obter os pesos e variáveis de um modelo existente já treinado com muitos dados e usá-lo na sua própria tarefa de dados e previsão.

Um dos muitos benefícios do aprendizado por transferência é que você não precisa fornecer tantos dados de treinamento, como se começasse do zero. Mas, de onde vêm esses modelos pré-existentes? É aí que o TensorFlow Hub ajuda, oferecendo um repositório completo de pontos de controle já existentes para vários tipos de modelo: imagens, texto e outros. Nesta postagem, mostrarei como criar um modelo para prever o gênero de um filme com base na sua descrição usando o módulo de texto do TensorFlow Hub.

Você pode executar esse modelo no navegador usando o Colab, sem necessidade de configurar nada.

Importação e pré-processamento de dados

Para esse modelo, usaremos este conjunto de dados de filmes incrível da Kaggle, que é de domínio público e contém dados de mais de 45.000 filmes. O conjunto tem diversos dados sobre cada filme, mas, para simplificar as coisas, vamos usar somente as descrições (chamadas de "overview", ou visão geral) e os gêneros. Esta é uma visualização do conjunto de dados do Kaggle:

Primeiro, importamos as bibliotecas que usaremos para criar o modelo:

Disponibilizei um arquivo CSV desse conjunto de dados em um bucket público do Cloud Storage. Executaremos o comando abaixo para fazer download dos dados da nossa instância do Colab e lê-los como um dataframe do Pandas:

Para manter a simplicidade, vamos limitar os gêneros possíveis:

Limitaremos o conjunto de dados a filmes desses gêneros que tenham descrição. Depois, poderemos dividir os dados em conjuntos de treinamento e de teste aplicando uma divisão de 80% para treinamento e 20% para teste:

Criação da camada de incorporação com o TF Hub

É surpreendente como uma incorporação com o TF Hub usa tão pouco código. Nosso modelo só terá um recurso (a descrição) e será representado por uma coluna incorporada. As incorporações de texto criam uma forma de representar partes do texto em espaço de vetor. Portanto, palavras ou frases parecidas ficam mais próximas no espaço de incorporação (leia mais sobre esse assunto aqui). Você pode criar vetores de incorporação de texto do zero usando apenas seus próprios dados. O TF Hub simplifica esse processo disponibilizando incorporações de texto já treinadas com diversos dados de texto.

Para texto em inglês, o TF Hub oferece diversas incorporações treinadas com vários tipos de dado de texto:

  • Codificador universal de sentenças: para entradas de texto mais longas
  • ELMo: incorporações profundas treinadas com o 1B Word Benchmark
  • Incorporações do modelo de linguagem de rede neural: treinadas com o Google Notícias
  • Word2vec: treinada com a Wikipédia

As incorporações de texto pré-treinadas que você escolher são um hiperparâmetro no seu modelo. Por isso, é melhor experimentar com outras e ver qual delas tem a maior precisão. Comece com o modelo que foi treinado com textos mais parecidos ao seu. Como nossas descrições de filme são entradas mais longas, notei que consegui a maior precisão com as incorporações do codificador universal de sentenças. Ele codifica as descrições em vetores de texto altamente dimensionais. Note que esse modelo em particular é bem grande e vai ocupar 1 GB.

Podemos usar hub.text_embedding_column para criar uma coluna de recursos para essa camada em uma linha de código, passando a ela o nome da camada ("movie_descriptions") e o URL do modelo do TF Hub que usaremos:

Veja que pode levar algum tempo para a execução dessa célula, já que está fazendo o download das incorporações pré-treinadas.

O melhor é que não precisamos de pré-processamento para inserir as descrições em texto nas incorporações de palavras pré-treinadas. Se fôssemos criar esse modelo do zero, teríamos que converter as descrições em vetores. No entanto, com a coluna TF Hub, podemos passar as strings de descrição diretamente para o modelo.

Transformação de rótulos em codificações multi-hot

Como um filme muitas vezes tem diversos gêneros, nosso modelo retornará os vários rótulos possíveis para cada filme. No momento, nossos gêneros são uma lista de strings de cada filme (como ["Action", "Adventure"], ou ação, aventura). Como todos os rótulos têm que ter o mesmo tamanho, transformaremos essas listas em vetores multi-hot de dígitos 1 e 0, que correspondem aos gêneros presentes em uma determinada descrição. O vetor multi-hot de um filme de ação e aventura (Action e Adventure) ficaria assim:

Para transformar os rótulos de string em vetores multi-hot em poucas linhas de código, usaremos um utilitário da biblioteca scikit-learn chamado MultiLabelBinarizer:

Você pode imprimir encoder.classes_ para ver uma lista de todas as classes de string que o modelo está prevendo.

Desenvolvimento e treinamento de um modelo de DNNEstimator

Para o nosso modelo, usaremos um DNNEstimator para criar uma rede neural profunda que retorna um vetor multi-hot, já que todo filme pode ter 0 ou mais rótulos possíveis (isso é diferente de um modelo em que cada entrada tem exatamente um rótulo). O primeiro parâmetro que passamos ao DNNEstimator é chamado de "head" (cabeça) e define o tipo de rótulos que nosso modelo deve esperar. Como queremos que o nosso modelo gere diversos rótulos, usaremos "multi_label_head":

Agora, podemos passar isso quando instanciarmos o DNNEstimator. O parâmetro "hidden_units" indica quantas camadas teremos na nossa rede. Esse modelo usa 2 camadas: a primeira tem 64 neurônios e a segunda tem 10. O número e o tamanho das camadas é um hiperparâmetro. Portanto, o ideal é experimentar valores diferentes para ver qual funciona melhor com o conjunto de dados. Por fim, passamos nossas colunas de recurso ao Estimator. Nesse caso, só temos uma (a descrição), e já a definimos como uma coluna de incorporação do TF Hub acima para podermos passá-la aqui como uma lista:

Já está quase tudo pronto para treinar o modelo. Antes de podermos treinar nossa instância do estimador, precisamos definir a função "input" (entrada) do treinamento. Essa função conecta nossos dados ao modelo. Aqui, vamos usar um "numpy_input_fn" e inserir os dados no nosso modelo como matrizes "numpy":

Os parâmetros "batch_size" e "num_epochs" da nossa função "input" são hiperparâmetros. "batch_size" diz ao modelo quantos exemplos serão passados ao modelo em uma iteração e "num_epochs" é o número de vezes que nosso modelo analisará todo o conjunto de treinamento.

Chegou a hora de treinar o modelo. Fazemos isso com uma linha de código:

Para avaliar a precisão do nosso modelo, criamos um eval "input_function" com os dados do teste e chamamos "estimator.evaluate()":

Esse modelo atingiu 91,5% de área abaixo da curva (AUC) e 74% de precisão/recall. Os seus resultados podem variar um pouco.

Geração de previsões no modelo treinado

Chegamos na melhor parte: gerar previsões com dados que o nosso modelo nunca viu. Primeiro, vamos criar uma matriz com algumas descrições (peguei as descrições abaixo no IMDB):

Em seguida, vamos definir nossa função "input" de previsão e chamar "predict()":

Por fim, podemos iterar os resultados e exibir os 2 principais gêneros encontrados para cada filme junto com os valores de confiança:

Nosso modelo consegue marcar todas as descrições de filme acima corretamente.

Primeiros passos

Quer começar a desenvolver o seu próprio modelo com o TF Hub? Confira a documentação e os tutoriais. Veja o código completo do modelo que usamos aqui no GitHub ou no Colab. Em uma postagem futura, mostrarei como exportar esse modelo para operar no TensorFlow Serving ou no Cloud ML Engine, e como criar um aplicativo que gera previsões sobre novas descrições.

Se tiver alguma dúvida ou quiser fazer uma observação, fale comigo no Twitter: @SRobTweets.