NLP nas empresas | Como criar um modelo BERT de Question-Answering (QA) de desempenho aprimorado com AdapterFusion?

Pierre Guillou
12 min readAug 18, 2021
Um modelo BERT com ajuste fino para a tarefa de Perguntas e Respostas (QA: Question-Answering) usando AdapterFusion
Um modelo BERT com ajuste fino para a tarefa de Perguntas e Respostas (QA: Question-Answering) usando AdapterFusion

Seguindo nosso artigo apresentando os adapters da biblioteca de adapter-transformers e seus diversos interesses para empresas e organizações que desejam utilizar modelos de Inteligência Artificial (IA) para automatizar seus processos de NLP (Natural Language Processing) internos e externos, estamos publicando uma série de artigos acompanhados de notebooks e/ou scripts que são tutoriais que permitem implementar os adapters em seus negócios e atividades. Continuamos essa série com este artigo sobre o AdapterFusion que permite ajustar um modelo de linguagem natural como BERT para a tarefa de Perguntas e Respostas (QA: Question-Answering) com um desempenho melhor que o mesmo modelo com adapters mas sem AdapterFusion.

NLP nas empresas | Adapter-Transformers Para Dummies

Sumário

  • Contexto
  • Modelo de linguagem natural ajustado para a tarefa de Perguntas e Respostas (QA: Question-Answering) com AdapterFusion
  • Tutorial | Ajusto fino do BERT geral em português para a tarefa QA com o dataset SQuAD 1.1 e AdapterFusion
    - Notebooks
    - Mudanças principais em notebooks e scripts originais
    - Configuração dos modelos
    - Resultados de treinamento
    - Número de parâmetros do modelo com AdapterFusion
  • Uso do modelo com AdapterFusion

Contexto

No artigo “NLP nas empresas | Uma solução para colocar os modelos BERT em produção com Adapters para transformers”, apresentamos a biblioteca adapter-transformers que permite treinar módulos chamados adapter a partir de um modelo transformer do tipo BERT sem alterar os valores de seus embeddings, nem os dos parâmetros de suas camadas.

O interesse é imediato: assim, é possível treinar tantos adapters quanto uma empresa ou organização tenha tarefas de NLP (Natural Language Processing) para realizar em um determinado idioma e isso a partir do mesmo modelo de linguagem natural. Na produção, apenas esse modelo deve ser armazenado e acessível por meio de uma API, bem como os vários adapters.

Essa solução simplifica muito o uso desses diferentes modelos de NLP (um modelo = modelo original + adapter), pois apenas um modelo de linguagem natural deve ser armazenado (o modelo original) mais os adapters (o peso de um task adapter é apenas entre 1 e 3% do peso do modelo original).

Imagine se uma empresa ou organização tivesse que arquivar tantos modelos originais ajustados quanto tem tarefas de NLP quando um modelo BERT large pesa mais de 1,3 GB…

Modelo de linguagem natural ajustado para a tarefa de Perguntas e Respostas (QA: Question-Answering) com AdapterFusion

Na Internet hoje é fácil baixar um modelo de linguagem natural como o BERT que já é treinado em sua língua. Por exemplo, existe o modelo BERT base em português da Neuralmind e o modelo BERT large em português da Neuralmind que estão no hub de modelos de Hugging Face.

Como explicamos no artigo “NLP nas empresas | Como ajustar um modelo de linguagem natural como BERT a um novo domínio linguístico com um Adapter?”, é aconselhável ajustar esse modelo ao domínio linguístico específico de seus dados (saúde, jurídico, etc.) antes de usar esse modelo ajustado para se especializar em tarefas de NLP como a classificação de tokens (NER), a busca por respostas a perguntas (QA: Question-Answering), a classificação de sentenças ou documentos, etc.

Esse ajuste (finetuning) com a biblioteca adapter-transformers fornecerá o lang adapter e a head do modelo de NLP original usado.

Em segunda etapa, pode treinar seu modelo original para uma tarefa específica, como Classificação de tokens (NER) (leia este artigo) ou Perguntas e Respostas (QA) (leia este artigo), treinando um task adapter. Esse treinamento só se relacionará aos novos parâmetros, aqueles do task adapter, e não aos do modelo original, nem aos do lang adapter se decidir acrescentá-lo ao modelo a ser treinado.

Porém, como combinar os conhecimentos adquiridos para cada tarefa NLP (pelo treinamento de um task adapter) de forma a obter um modelo com maior conhecimento linguístico, o que deve ajudar a obter um melhor desempenho para cada tarefa?

A resposta pode ser encontrada no artigo “AdapterFusion: Non-Destructive Task Composition for Transfer Learning”. A ideia é a seguinte:

como cada tarefa NLP corresponde a um task adapter, basta fazer o download deles no modelo de linguagem natural e incluir um novo adapter chamado AdapterFusion, cuja função é ponderar as saídas dos task adapters em relação à tarefa NLP para a qual o modelo vai ser treinado.

Assim, o modelo inicial que vai ser treinado para uma tarefa NLP não é mais o modelo de linguagem natural original, mas esse modelo com, além disso, conhecimentos de diferentes tarefas NLP que são codificados nos task adapters. Já para um ser humano que utiliza conhecimentos de outras áreas e/ou tarefas para realizar uma nova tarefa, esse modelo com tasks adapters e AdapterFusion será treinado seguindo o mesmo conceito.

Observação: a arquitetura do AdapterFusion é detalhada no artigo já citado e veja a seguir seus gráficos e explicações.

arquitetura do AdapterFusion (credito: “AdapterFusion: Non-Destructive Task Composition for Transfer Learning”)
arquitetura do AdapterFusion (credito: AdapterFusion: Non-Destructive Task Composition for Transfer Learning”)

Finalmente, é bom relatar as seguintes informações: o conceito de modelo multitarefa já existe em NLP, mas conforme explicado no artigo sobre AdapterFusion, é difícil colocá-lo em prática seguindo o método de treinamento sequencial (risco de Catastrophic Forgetting) ou paralelo (desequilíbrios dos tamanhos dos datasets de treinamaneto por tarefas que levam a overfitting ou underfitting) de todas as camadas do modelo original de linguagem natural. O AdapterFusion torna a multitarefa eficiente muito mais fácil.

Tutorial | Ajusto fino do BERT geral em português para a tarefa QA com o dataset SQuAD 1.1 e AdapterFusion

Notebook

Estamos usando aqui dataset SQuAD 1.1 em português (versão em português do dataset SQuAD v1.1 inglês cuja tradução foi feita pelo grupo Deep Learning Brasil: squad-pt.tar.gz no Google Drive (fonte)) para treinar o modelo na tarefa de Question-Answering (QA) com a biblioteca adapter-transformers.

Por fazer isso, publicamos um notebook (question_answering_adapter_fusion.ipynb (versão nbviewer)) realizado a partir dos seguintes notebooks e scripts para o ajuste fino de um Modelo de Linguagem de tipo transformer como o BERT (base ou grande) com qualquer datasets para a tarefa QA usando AdapterFusion:

Esse notebook pode ser usado com BERT base or large e com qualquer dataset para a tarefa QA usando AdapterFusion.

Nota: o notebooks está na pasta question-answering no github.

Mudanças principais em notebooks e scripts originais

Atualizamos os notebooks e scripts originais com as seguintes alterações:

  • EarlyStopping: selecionando o modelo com a maior precisão de avaliação (paciência de 3 antes de terminar o treinamento).
  • MAD-X 2.0: opção que permite não treinar adapters na última camada do modelo transformer (leia a página 6 de UNKs Everywhere: Adapting Multilingual Language Models to New Scripts).
  • Stack method para os lang e task adapters quando um lang adapter é carregado (doc).
  • Método AdapterFusion de 2 task adapters (consulte “AdapterFusion: Non-Destructive Task Composition for Transfer Learning”).
  • Houlsby MHA last layer (para a configuração de Houlsby) que não permite treinar o task adapter após a camada de Feed Forward, mas somente após a de MHA (Multi-Head Attention) no último bloco transformer.

Configuração dos modelos

Para fazer o ajuste fino do modelo BERT para a tarefa QA usando AdapterFusion, precisamos inserir os task adapters já treinados (para tarefas NLP diferentes) no nível de cada uma das camadas transformer do modelo original, o lang adapter já treinado quando for necessário (modelos com adaptação ao domínio do dataset de QA), e adicionar um AdapterFusion para ser treinado.

task adapters

lang adapter

Quando treinamos os modelos (5 e 6) com adaptação ao domínio do dataset de QA (dataset SQuAD 1.1 pt), inserimos o LANG adapter treinado a respeito desse domínio (veja o artigo “NLP nas empresas | Como ajustar um modelo de linguagem natural como BERT a um novo domínio linguístico com um Adapter?”).

AdapterFusion

Unicamente os parâmetros do AdapterFusion foram treinados para a tarefa de QA (todos os outros parâmetros, os do modelo original e os dos lang e task adapters, foram congelados).

Resultados de treinamento

Para comparar o desempenho das 2 configurações (com ou sem lang adapter) entre si, com os modelos correspondentes com adapters mas sem AdapterFusion, e com um modelo BERT sem adapter ajustado de uma forma clássica (ajuste fino de todas as camadas do modelo), treinamos os 5 modelos seguintes para a tarefa QA com o dataset SQuAD 1.1 em português:

  • (modelo 1 — original) modelo BERT Neuralmind large sem adapter (esse modelo QA é o nosso modelo de referência; ele está online no model hub da Hugging Face: Portuguese BERT large cased QA (Question Answering), finetuned on SQUAD v1.1).
  • (modelo 2) modelo BERT Neuralmind large sem adapter (o original) já ajustado aos textos do dataset SQuAD 1.1 em português e treinado para a tarefa QA.
  • (modelo 3) o modelo original com task adapter (QA) pfeiffer mas sem adapter no último bloco transformer (se chama MAD-X 2.0) e sem lang adapter.
  • (modelo 4 — AdapterFusion) o modelo original com task adapter (QA) pfeiffer, com task adapter (NER) pfeiffer e com AdapterFusion mas sem adapter no último bloco transformer (se chama MAD-X 2.0) e sem lang adapter.
  • (modelo 5) o modelo original com task adapter (QA) pfeiffer e com lang adapter pfeiffer+inv mas sem adapter no último bloco transformer (se chama MAD-X 2.0).
  • (modelo 6 — AdapterFusion) o modelo original com task adapter (QA) pfeiffer, com task adapter (NER) pfeiffer, com AdapterFusion e com lang adapter pfeiffer+inv mas sem adapter no último bloco transformer (se chama MAD-X 2.0).

Aqui estão os resultados:

resultados dos 4 modelos ajustados para a tarefa QA com o dataset SQuAD 1.1 pt e sem/com AdapterFusion (cor verde: número superior ao do modelo oficial no model hub da Hugging Face; cor vermelha: número inferior ao mesmo modelo oficial)
resultados dos 4 modelos ajustados para a tarefa QA com o dataset SQuAD 1.1 pt e sem/com AdapterFusion (cor verde: número superior ao do modelo oficial no model hub da Hugging Face; cor vermelha: número inferior ao mesmo modelo oficial)

Podemos verificar nessa tabela de resultados que ao treinar com AdapterFusion permite superar o desempenho do modelo correspondente sem ele (modelo 4 vs 3, e modelo 6 vs 5).

O melhor modelo com adapters é o modelo 6 (modelo com AdapterFusion, lang e task adapters) que conseguiu um f1 superior a 83.71% (83.7165%), seja uma diminuição de apenas 0.85% em comparação do f1 do modelo publicado no modelo hub da Hugging Facemas com apenas 21.7% de novo parâmetros treinado (os do AdapterFusion) (ao total, esse modelo 6 tem 30.95% de parâmetros de tipo adapter: os dos lang e task adapters, e do AdapterFusion).

Observação: o modelo 5 correspondente mas sem AdapterFusion conseguiu um f1 inferior de 83.60%, o que confirma o interesse de ter um modelo multitarefas graças aos task adapters e o AdapterFusion.

Em relação aos hiperparâmetros de treinamento, podemos destacar o fato de que sempre usamos os mesmos (taxa de aprendizagem de 3e-5, batch size de 32) para os modelos com task adapters e AdapterFusion! Além disso, treinamos os modelos com AdapterFusion (4 e 6) com um learning rate e um número de épocas 3 vezes menor do que os modelos sem (3 e 5), o que faz sentido (os modelos com AdapterFusion já possuem o task adapter QA treinado).

Em resumo, como procuramos eficácia em produção (em particular, acurácia e velocidade no uso do modelo), poderíamos usar essa configuração com AdapterFusion.

Número de parâmetros do modelo com AdapterFusion

Se usar o modelo BERT large em português da Neuralmind, pode calcular a porcentagem de parâmetros do modelo com lang e task adapters e AdapterFusion em comparação com ao modelo sem adapter.

O aumento mínimo é de 23.54% (modelo 4) e o máximo de 30.95% (modelo 6).

No caso do modelo 6 (modelo com o melhor f1), significa que em vez de armazenar a cada vez um modelo QA (a cada corpus especifico, um modelo QA) de 1.34 GB (BERT large da Neuralmind), vai armazenar 30.95% x 1.34 GB= 414.73MB (+9,2 KB para os parâmetros de head do modelo).

Interessante. No entanto, esse número de parâmetros de tipo adapter a serem armazenados aumentará com cada novo task adapter adicionado para obter um modelo de multitarefa ainda melhor. Os autores da biblioteca de adapter-transformers refletiram sobre isso e publicaram “AdapterDrop: On the Efficiency of Adapters in Transformers” para treinar light-weight adapters.

Aqui está o resumo em inglês:

Massively pre-trained transformer models are computationally expensive to fine-tune, slow for inference, and have large storage requirements. Recent approaches tackle these shortcomings by training smaller models, dynamically reducing the model size, and by training light-weight adapters. In this paper, we propose AdapterDrop, removing adapters from lower transformer layers during training and inference, which incorporates concepts from all three directions. We show that AdapterDrop can dynamically reduce the computational overhead when performing inference over multiple tasks simultaneously, with minimal decrease in task performances. We further prune adapters from AdapterFusion, which improves the inference efficiency while maintaining the task performances entirely.

Uso do modelo com AdapterFusion

Em primeiro lugar, deve baixar o modelo original do hub de modelos da Hugging Face:

from transformers import AutoModelForQuestionAnswering, AutoTokenizermodel_checkpoint = "neuralmind/bert-large-portuguese-cased"tokenizer_qa = AutoTokenizer.from_pretrained(model_checkpoint)
model_qa = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint)

Então, é necessário acrescentar o lang adapter que treinamos (porque a gente o usou durante o treinamento):

# load the language adapter without head
task_mlm_load_as = 'mlm'
lang_adapter_name = model_qa.load_adapter(
load_lang_adapter,
config=lang_adapter_config,
load_as=task_mlm_load_as,
with_head=False
)

Depois, precisamos acrescentar os task adapters QA e NER que usamos durante o treinamento:

task_ad1 = "qa"
task_ad2 = "ner"
adapter_name_ad1 = model_qa.load_adapter(
load_qa_adapter,
config=qa_adapter_config,
load_as=load_as_ad1,
with_head=False
)

adapter_name_ad2 = model_qa.load_adapter(
load_ner_adapter,
config=ner_adapter_config,
load_as=load_as_ad2,
with_head=False
)

Agora, temos de acrescentar o AdapterFusion que treinamos e ativar esses 3 adapters no forward do nosso modelo:

model_qa.load_adapter_fusion(path_to_save_adapter)

model_qa.load_head(path_to_save_adapter)

adapter_setup = [
[
load_as_ad1,
load_as_ad2
]
]
# Set the adapters to be used in every forward pass
model_qa.set_active_adapters([lang_adapter_name,adapter_setup[0]])

Finalmente, podemos usar nosso modelo com AdapterFusion para encontrar as respostas às perguntas em um texto pelo código seguinte:

from transformers import pipeline
nlp = pipeline("question-answering", model=model_qa, tokenizer=tokenizer_qa)

… com o texto seguinte:

text = """
A pandemia de COVID-19, também conhecida como pandemia de coronavírus, é uma pandemia em curso de COVID-19,
uma doença respiratória causada pelo coronavírus da síndrome respiratória aguda grave 2 (SARS-CoV-2).
O vírus tem origem zoonótica e o primeiro caso conhecido da doença remonta a dezembro de 2019 em Wuhan, na China.
Em 20 de janeiro de 2020, a Organização Mundial da Saúde (OMS) classificou o surto
como Emergência de Saúde Pública de Âmbito Internacional e, em 11 de março de 2020, como pandemia.
Em 18 de junho de 2021, 177 349 274 casos foram confirmados em 192 países e territórios,
com 3 840 181 mortes atribuídas à doença, tornando-se uma das pandemias mais mortais da história.
Os sintomas de COVID-19 são altamente variáveis, variando de nenhum a doenças com risco de morte.
O vírus se espalha principalmente pelo ar quando as pessoas estão perto umas das outras.
Ele deixa uma pessoa infectada quando ela respira, tosse, espirra ou fala e entra em outra pessoa pela boca, nariz ou olhos.
Ele também pode se espalhar através de superfícies contaminadas.
As pessoas permanecem contagiosas por até duas semanas e podem espalhar o vírus mesmo se forem assintomáticas.
"""

… e a questão seguinte:

question = "Onde foi descoberta a Covid-19?"
result = nlp(question=question, context=context)

Aqui está o resultado:

Answer: 'Wuhan, na China'

Et voilà :-)

Nota: veja o notebook para ter acesso ao código correspondente a essa parte.

Sobre o autor: Pierre Guillou é Head of AI na startup de HealthTech Laudite (Brasil), e consultor de IA no Brasil e na França. Entre em contato com ele por meio de seu perfil no LinkedIn.

--

--