
O BERT é uma rede neural do Google, que mostrou por uma grande margem os resultados mais recentes em várias tarefas. Usando o BERT, você pode criar programas de IA para processar um idioma natural: responder a perguntas de qualquer forma, criar bots de bate-papo, tradutores automáticos, analisar texto e assim por diante.
O Google publicou modelos pré-treinados de BERT, mas, como geralmente acontece com o Machine Learning, eles sofrem com a falta de documentação. Portanto, neste tutorial, aprenderemos como executar a rede neural BERT no computador local, bem como na GPU de servidor livre no Google Colab.
Por que é necessário?
Para enviar texto para a entrada de uma rede neural, você precisa de alguma forma apresentá-lo na forma de números. É mais fácil fazer essa letra por letra, aplicando uma letra a cada entrada da rede neural. Cada letra será codificada com um número de 0 a 32 (mais algum tipo de margem para sinais de pontuação). Este é o chamado nível de caractere.
Porém, resultados muito melhores são obtidos se apresentarmos propostas não por uma letra, mas submetendo a cada entrada da rede neural imediatamente uma palavra inteira (ou pelo menos sílabas). Já será um nível de palavra. A opção mais fácil é compilar um dicionário com todas as palavras existentes e alimentar a rede com o número de palavras neste dicionário. Por exemplo, se a palavra "cachorro" estiver neste dicionário em 1678, digite o número 1678 para a entrada da rede neural para essa palavra.
Mas apenas em uma linguagem natural, com a palavra "cachorro", muitas associações surgem ao mesmo tempo em uma pessoa: "fofo", "mal", "amigo de uma pessoa". É possível codificar de alguma maneira esse recurso de nosso pensamento na apresentação para a rede neural? Acontece que você pode. Para fazer isso, basta reordenar os números das palavras para que as palavras com significado próximo fiquem lado a lado. Que seja, por exemplo, para "cachorro" o número 1678 e para a palavra "fofo" o número 1680. E para a palavra "bule" o número é 9000. Como você pode ver, os números 1678 e 1680 estão muito mais próximos um do outro do que o número 9000.
Na prática, a cada palavra é atribuído não um número, mas várias - um vetor, digamos, de 32 números. E as distâncias são medidas como as distâncias entre os pontos que esses vetores apontam no espaço da dimensão correspondente (para um vetor com 32 dígitos de comprimento, este é um espaço com 32 dimensões ou com 32 eixos). Isso permite comparar uma palavra de uma vez com várias que têm significado próximo (dependendo de qual eixo contar). Além disso, operações aritméticas podem ser realizadas com vetores. Um exemplo clássico: se você subtrair o vetor "homem" do vetor que denota a palavra "rei" e adicionar o vetor para a palavra "mulher", obterá um determinado vetor de resultado. E ele corresponderá milagrosamente à palavra "rainha". E, de fato, "rei é homem + mulher = rainha". A magia! E este não é um exemplo abstrato, mas realmente acontece . Considerando que as redes neurais estão bem adaptadas para transformações matemáticas sobre suas entradas, isso aparentemente fornece uma eficiência tão alta desse método.
Essa abordagem é chamada de casamentos. Todos os pacotes de aprendizado de máquina (TensorFlow, PyTorch) permitem que a primeira camada da rede neural coloque uma camada especial de Camada de incorporação, que faz isso automaticamente. Ou seja, na entrada da rede neural, fornecemos o número habitual de palavras no dicionário, e a Camada de incorporação, auto-aprendizagem, traduz cada palavra em um vetor do comprimento especificado, digamos, 32 números.
Mas eles rapidamente perceberam que é muito mais lucrativo pré-treinar essa representação vetorial de palavras em um imenso corpus de textos, por exemplo, em toda a Wikipedia, e usar vetores prontos em redes neurais específicas, em vez de treiná-los novamente.
Existem várias maneiras de representar palavras como vetores: elas evoluíram gradualmente: word2vec, GloVe, Elmo.
No verão de 2018, a OpenAI notou que, se você treina uma rede neural na arquitetura Transformer em grandes volumes de texto, ela inesperadamente e por uma grande margem mostra excelentes resultados em muitos tipos diferentes de tarefas de processamento de linguagem natural. De fato, uma rede neural desse tipo cria representações vetoriais para palavras e até frases inteiras. E, apoiando-se nesse modelo de linguagem em um pequeno bloco de um par de camadas adicionais de neurônios, você pode treinar essa rede neural para qualquer tarefa.
O BERT do Google é uma rede GPA avançada da OpenAI (bidirecional em vez de unidirecional etc.), também baseada na arquitetura Transformer. No momento, o BERT é o estado da arte em quase todos os benchmarks populares da PNL.
Como eles fizeram isso
A idéia por trás do BERT é muito simples: vamos alimentar a rede neural com frases nas quais substituímos 15% das palavras por [MASK] e treinar a rede neural para prever essas palavras mascaradas.
Por exemplo, se enviarmos a frase “eu vim para [MASK] e comprei [MASK]” ”para a entrada da rede neural, ela deverá mostrar as palavras“ store ”e“ milk ”na saída. Este é um exemplo simplificado da página oficial do BERT; em sentenças mais longas, o leque de opções possíveis se torna menor e a resposta da rede neural é inequívoca.
E, para que a rede neural aprenda a entender as relações entre diferentes frases, vamos treiná-la adicionalmente para prever se a segunda frase é uma continuação lógica da primeira. Ou é alguma frase aleatória que não tem nada a ver com a primeira.
Então, por duas frases: "Eu fui à loja". e “E comprei leite lá.”, a rede neural deve responder que isso é lógico. E se a segunda frase é "céu cruciano Plutão", devo responder que esta proposta não tem nada a ver com a primeira. Vamos brincar com os dois modos BERT abaixo.
Assim, treinando a rede neural no corpus de textos da Wikipedia e na coleção de livros BookCorpus por 4 dias às 16 TPU, obtivemos o BERT.
Instalação e configuração
Nota : nesta seção, iniciaremos e jogaremos com o BERT no computador local. Para executar esta rede neural em uma GPU local, você precisará de um NVidia GTX 970 com 4 GB de memória de vídeo ou superior. Se você deseja executar o BERT em um navegador (você nem precisa de uma GPU no seu computador para isso), acesse a seção Google Colab.
Primeiro instale o TensorFlow, se você ainda não o possui, seguindo as instruções em https://www.tensorflow.org/install . Para oferecer suporte à GPU, você deve primeiro instalar o CUDA Toolkit 9.0, depois o cuDNN SDK 7.2 e somente o TensorFlow com suporte à GPU:
pip install tensorflow-gpu
Basicamente, isso é suficiente para executar o BERT. Mas não há instruções, como tal, você pode compor por si mesmo classificando as fontes no arquivo run_classifier.py (a situação usual no Machine Learning é quando você precisa acessar as fontes em vez da documentação). Mas vamos facilitar e usar o shell Keras BERT (também pode ser útil para ajustar a rede posteriormente, porque fornece uma interface Keras conveniente).
Para fazer isso, instale o próprio Keras:
pip install keras
E depois de Keras BERT:
pip install keras-bert
Também precisaremos do arquivo tokenization.py do github BERT original. Clique no botão Raw e salve-o na pasta com o script futuro, ou faça o download de todo o repositório e leve o arquivo de lá ou faça uma cópia do repositório com este código https://github.com/blade1780/bert .
Agora é hora de baixar a rede neural pré-treinada. Existem várias opções para o BERT, todas listadas na página oficial do github.com/google-research/bert . Tomaremos o "BERT-Base, Multilingual Multilíngüe" multilíngue universal, para 104 idiomas. Faça o download do arquivo multi_cased_L-12_H-768_A-12.zip (632 Mb) e descompacte-o na pasta com o script futuro.
Está tudo pronto, crie o arquivo BERT.py e haverá um pouco de código.
Importar bibliotecas necessárias e definir caminhos
Como teremos que traduzir linhas de texto comuns em um formato especial de tokens, criaremos um objeto especial para isso. Preste atenção em do_lower_case = False, pois estamos usando o modelo Cased BERT, que diferencia maiúsculas de minúsculas.
tokenizer = tokenization.FullTokenizer(vocab_file=vocab_path, do_lower_case=False)
Modelo de carregamento
model = load_trained_model_from_checkpoint(config_path, checkpoint_path, training=True) model.summary()
O BERT pode funcionar de dois modos: adivinhar as palavras perdidas na frase ou adivinhar se a segunda frase é lógica depois da primeira. Faremos as duas opções.
Para o primeiro modo, você precisa enviar uma frase no formato:
[CLS] [MASK] [MASK]. [SEP]
A rede neural deve retornar uma frase completa com as palavras preenchidas no lugar das máscaras: "Vim à loja e comprei leite".
Para o segundo modo, ambas as frases separadas por um separador devem ser alimentadas à entrada da rede neural:
[CLS] . [SEP] . [SEP]
A rede neural deve responder se a segunda frase é uma continuação lógica da primeira. Ou é uma frase aleatória que não tem nada a ver com a primeira.
Para que o BERT funcione, você precisa preparar três vetores, cada um com um comprimento de 512 números: token_input, seg_input e mask_input.
Token_input armazenará nosso código fonte traduzido em tokens usando o tokenizer. A frase na forma de índices no dicionário estará no início desse vetor e o restante será preenchido com zeros.
Em mask_input, devemos colocar 1 para todas as posições em que a máscara [MASK] está e preencher o restante com zeros.
Em seg_input, devemos indicar a primeira frase (incluindo o CLS inicial e o separador SEP) como 0, a segunda frase (incluindo o SEP final) como 1 e preencher o restante até o final do vetor com zeros.
O BERT não usa um dicionário de palavras inteiras, mas as sílabas mais comuns. Embora também tenha palavras inteiras. Você pode abrir o arquivo vocab.txt na rede neural baixada e ver quais palavras a rede neural usa na entrada. Há palavras inteiras como a França. Mas a maioria das palavras em russo precisa ser dividida em sílabas. Portanto, a palavra "veio" deve ser dividida em "com" e "## foi". Para ajudar na conversão de linhas regulares de texto no formato exigido pelo BERT, usamos o módulo tokenization.py.
Modo 1: Previsão de palavras fechadas por token [MASK] em uma frase
A frase de entrada que é alimentada na entrada da rede neural
sentence = ' [MASK] [MASK].' print(sentence)
Converta-o em tokens. O problema é que o tokenizer não pode processar marcas de serviço como [CLS] e [MASK], embora o vocab.txt as possua no dicionário. Portanto, teremos que quebrar manualmente nossa linha com marcadores [MASK] e extrair dele partes de texto sem formatação para convertê-lo em tokens BERT usando o tokenizador. Adicione também [CLS] no início e [SEP] no final da frase.
sentence = sentence.replace(' [MASK] ','[MASK]'); sentence = sentence.replace('[MASK] ','[MASK]'); sentence = sentence.replace(' [MASK]','[MASK]')
Os tokens agora têm tokens que são garantidos para serem convertidos em índices no dicionário. Vamos fazer isso:
token_input = tokenizer.convert_tokens_to_ids(tokens)
Agora, em token_input, há uma série de números (números de palavras no dicionário vocab.txt) que precisam ser alimentados na entrada da rede neural. Resta apenas estender esse vetor a um comprimento de 512 elementos. A construção Python [0] * length cria uma matriz de comprimento de comprimento, preenchida com zeros. Basta adicioná-lo aos nossos tokens, que em python combinam duas matrizes em uma.
token_input = token_input + [0] * (512 - len(token_input))
Agora crie uma máscara de 512 cm de comprimento, colocando 1 em todos os lugares, onde o número 103 aparece nos tokens (que corresponde ao marcador [MASK] no dicionário vocab.txt) e preencha o restante com 0:
mask_input = [0]*512 for i in range(len(mask_input)): if token_input[i] == 103: mask_input[i] = 1
Para o primeiro modo de operação BERT, seg_input deve ser completamente preenchido com zeros:
seg_input = [0]*512
A última etapa, você precisa converter matrizes python em matrizes numpy com forma (1.512), para as quais as colocamos em uma sub-matriz []:
token_input = np.asarray([token_input]) mask_input = np.asarray([mask_input]) seg_input = np.asarray([seg_input])
OK, pronto. Agora execute a previsão da rede neural!
predicts = model.predict([token_input, seg_input, mask_input])[0] predicts = np.argmax(predicts, axis=-1) predicts = predicts[0][:len(tokens)]
Agora formate o resultado dos tokens de volta para uma sequência separada por espaços
out = []
E produza o resultado:
print('Result:', out)
No nosso exemplo, para a frase "eu vim para [MASK] e comprei [MASK]". a rede neural produziu o resultado "house" e "it": "vim para a casa e comprei". Bem, não é tão ruim pela primeira vez. Comprar uma casa é definitivamente melhor que o leite).
Outros exemplos (não dou exemplos malsucedidos, há muito mais que bem-sucedidos. Na maioria dos casos, a rede dá uma resposta vazia):A Terra é a terceira [MÁSCARA] do Sol
Resultado: Estrela
melhor sanduíche [MÁSCARA] com manteiga
Resultado: Atende
depois do almoço [MASK] deve dormir
Resultado: deste
afaste-se de [MASK]
Resultado: ## oh - isso é algum tipo de maldição? )
[MASK] da porta
Resultado: visualizar
Com [MASK] martelo e pregos pode fazer gabinete
Resultado: ajuda
E se amanhã não for? Hoje, por exemplo, não é [MÁSCARA]!
Resultado: será
Como você se cansa de ignorar o [MASK]?
Resultado: ela
Há lógica cotidiana, há lógica feminina, mas nada se sabe sobre o homem [MÁSCARA]
Resultado: Filosofia
Nas mulheres, aos trinta anos, forma-se uma imagem do príncipe, que se encaixa em qualquer [MÁSCARA].
Resultado: homem
Por maioria de votos, Branca de Neve e os sete anões votaram em [MASK], com um voto contra.
Resultado: vila - a primeira letra está correta
Classifique sua tédio em uma escala de 10 pontos: [MASK] points
Resultado: 10
Suas [MÁSCARA], [MÁSCARA] e [MÁSCARA]!
Resultado: me ame eu - não, BERT, eu não quis dizer nada
Você pode inserir frases em inglês (e qualquer em 104 idiomas, cuja lista está aqui )
[MASK] deve continuar!
Resultado: I
Modo 2: verificando a consistência de duas frases
Definimos duas frases consecutivas que serão alimentadas na entrada da rede neural
sentence_1 = ' .' sentence_2 = ' .' print(sentence_1, '->', sentence_2)
Criaremos tokens no formato [CLS] frase_1 [SEP] frase_2 [SEP], convertendo texto sem formatação em tokens usando o tokenizer:
tokens_sen_1 = tokenizer.tokenize(sentence_1) tokens_sen_2 = tokenizer.tokenize(sentence_2) tokens = ['[CLS]'] + tokens_sen_1 + ['[SEP]'] + tokens_sen_2 + ['[SEP]']
Convertemos tokens de string em índices numéricos (números de palavras no dicionário vocab.txt) e estendemos o vetor para 512:
token_input = tokenizer.convert_tokens_to_ids(tokens) token_input = token_input + [0] * (512 - len(token_input))
A palavra máscara neste caso é completamente preenchida com zeros
mask_input = [0] * 512
Mas a máscara da proposta deve ser preenchida sob a segunda frase (incluindo o SEP final) com unidades e tudo mais com zeros:
seg_input = [0]*512 len_1 = len(tokens_sen_1) + 2
Passamos as frases pela rede neural (desta vez o resultado está em [1], e não em [0], como estava acima)
predicts = model.predict([token_input, seg_input, mask_input])[1]
E derivamos a probabilidade de que a segunda frase seja um conjunto de palavras normal, e não aleatório
print('Sentence is okey:', int(round(predicts[0][0]*100)), '%')
Em duas frases:
Eu vim para a loja. -> E comprei leite.
Resposta da rede neural:
A frase está ok: 99%
E se a segunda frase for "céu cruciano Plutão", a resposta será:
A sentença é razoável: 4%
Colab do Google
O Google fornece uma GPU gratuita para servidor Tesla K80 com 12 Gb de memória de vídeo (as TPUs estão agora disponíveis, mas sua configuração é um pouco mais complicada). Todo o código do Colab deve ser projetado como um notebook jupyter. Para iniciar o BERT em um navegador, basta abrir o link
http://colab.research.google.com/github/blade1780/bert/blob/master/BERT.ipynb
No menu Tempo de Execução , selecione Executar Tudo , para que pela primeira vez todas as células sejam iniciadas, o modelo é baixado e as bibliotecas necessárias estão conectadas. Concorde em redefinir todo o tempo de execução, se necessário.
Se algo desse errado ...Verifique se GPU e Python 3 estão selecionados no menu Tempo de execução -> Alterar tipo de tempo de execução
Se o botão de conexão não estiver ativo, clique nele para se conectar.
Agora altere a sentença das linhas de entrada, sentença_1 e sentença_2 , e clique no ícone Reproduzir à esquerda para iniciar apenas a célula atual. A execução de todo o notebook não é mais necessária.
Você pode executar o BERT no Google Colab mesmo a partir de um smartphone, mas se ele não abrir, pode ser necessário ativar a caixa de seleção Versão completa nas configurações do navegador.
O que vem a seguir?
Para treinar o BERT para uma tarefa específica, você precisa adicionar uma ou duas camadas de uma rede Feed Forward simples sobre ela e treiná-la apenas sem tocar na rede principal do BERT. Isso pode ser feito no TensorFlow ou no shell Keras BERT. Esse treinamento adicional para um domínio específico ocorre muito rapidamente e é completamente semelhante ao Ajuste fino em redes de convolução. Portanto, para a tarefa SQuAD, você pode treinar uma rede neural em uma TPU em apenas 30 minutos (em comparação com 4 dias na 16 TPU para treinar o próprio BERT).
Para fazer isso, você terá que estudar como as últimas camadas são representadas no BERT, além de ter um conjunto de dados adequado. Na página oficial do BERT https://github.com/google-research/bert, existem vários exemplos de tarefas diferentes, bem como instruções sobre como começar a reciclagem nas TPUs na nuvem. E tudo o resto terá que procurar na fonte nos arquivos run_classifier.py e extract_features.py .
PS
O bloco de anotações de código e jupiter do Google Colab apresentado aqui está hospedado no repositório .
Milagres não devem ser esperados. Não espere que o BERT fale como uma pessoa. O status do estado da arte não significa que o progresso na PNL tenha atingido um nível aceitável. Significa apenas que o BERT é melhor que os modelos anteriores, que foram ainda piores. A forte IA conversacional ainda está muito distante. Além disso, o BERT é principalmente um modelo de linguagem, não um bot de bate-papo pronto, por isso mostra bons resultados somente após a reciclagem para uma tarefa específica.