cpdoc / dhbb-nlp

processamentos DHBB
Other
5 stars 2 forks source link

NER e POS #55

Open arademaker opened 4 years ago

arademaker commented 4 years ago

De acordo com https://link.springer.com/article/10.1007/s42600-020-00067-7 parece que vale a pena conhecer

https://github.com/flairNLP/flair

Não apenas para POS tagging mas também para NER

arademaker commented 3 years ago

Em https://github.com/cpdoc/dhbb-ner, temos arquivos JSON produzidos pelo Watson Knowledge Studio. Ferramenta da IBM de anotação de entidades, relações e co-referencia. Antes de tentar qualquer outro sistema de NER como acima, queremos cruzar as anotações de NER com analises sintáticas. Isto nos permitirá priorizar as árvores sintáticas que precisamos corrigir no DHBB, e com isso teremos um ciclo de: revisão de anotação ~> treino UDPipe ~> anotação. Existem errors de anotação também veja http://dhbb.mybluemix.net/dhbb/document?id=212

« Antônio Nonato do Amaral» nasceu em Belém , no dia 16 de maio de 1926 , filho de [Domingos Araújo do Amaral] e de [Olinda Guimarães do Amaral] .

O nome da mãe foi erroneamente identificado como "Olinda Guimarães" apenas e "Amaral" foi erroneamente anotado como local. Para esta mesma sentença, o parser também cometeu um erro, ligando Amaral pela relação de nmod e não flat.

O que teremos e cruzar as anotações e achar inconsistências que possam nos sinalizar os erros frequentes. Todo segmentado anotado como uma entidade deve corresponder a uma subárvore na análise sintática.

O script deve receber como entrada um arquivo conllu e um arquivo json, ambos do mesmo documento. Teremos que usar os spans para alinhar sentenças e anotações de cada árvore. O que queremos é produzir como saida um conllup (https://universaldependencies.org/ext-format.html) com as árvores de sintáticas expandidas como as anotações de entidades encontradas no JSON. Simultaneamente, ou posteriormente, podemos ter uma validação destes arquivos conllup procurando por 'potenciais' inconsistências entre as anotações.

arademaker commented 3 years ago
  1. terminar parser json
  2. fazer lib hs-conllu funcionar
  3. transformar script em pacote (usando stack, provavelmente solução para 2 acima)
  4. executar o udpipe para arquivos
~/work/udpipe-1.2.0/bin-osx/udpipe --tokenizer="normalized_spaces;ranges" --tag --parse ~/work/udpipe-1.2.0/models/portuguese-bosque-ud-2.5-191206.udpipe < ../raw/1.raw > 1-new.conllu

obs: atencao para modelo usado com udpipe! ver dir udp para info de qual modelo mais atual temos e/ou seguir orientacoes para treinar.

  1. terminar codigo usando char span para verificar se cada entidade está em uma subárvore.
igorcj commented 3 years ago

@arademaker , agora que temos o parser do JSON completo e conseguimos rodar a Conllu.IO usando o stack, comecei a esboçar a verificação das entidades nas subarvores. Me deparei com o seguinte problema: a Aerson esta instalada no meu compilador padrão, mas o Conllu.IO só funciona rodando o ghci com o stack de dentro da pasta da biblioteca. Estou tentando encontrar uma forma de conseguir usar ambas bibliotecas ao mesmo tempo, provavelmente dentro do stack. Se tiver alguma sugestão ou referência para indicar, agradeço.

arademaker commented 3 years ago

Faça um fork do https://github.com/arademaker/test e comece de la colocando no src o código que lê o json. Depois em outro arquivo o código que lê o conllu usando a hs-conllu. No app ficará apenas o código que gera o executável final usando as funções do src

arademaker commented 3 years ago

Toda a idéia de offsets/sents estou reconsiderando. Principalmente porque todo o diretório sents pode ser considerado temporário.

De qq. modo, para avançarmos com esta tarefa, precisamos de uns arquivos conllu com offsets por tokens. Então rodei:

ar@leme sents %for f in ../raw/?.raw; do ~/work/apache-opennlp-1.9.3/bin/opennlp SentenceDetector ../src/model_opennlp.bin < $f > $(basename $f .raw).sent; done

e conferi os arquivos 1-9.sent manualmente. Depois executei o comando abaixo para produzir os arquivo .conllu:

ar@leme udp % ~/work/udpipe-1.2.0/bin-osx/udpipe --outfile={}.conllu --tokenizer="presegmented;normalized_spaces;ranges" --tag --parse ~/work/udpipe-1.2.0/models/portuguese-bosque-ud-2.5-191206.udpipe ../sents/?.sent

Note que o parametro presegmented faz o udpipe entender que o arquivo .sent tem uma sentença por linha. Como em cada sentença temos o metadado text = com o texto da sentença, os arquivos .sent não precisam ser preservados, podemos facilmente obte-los a partir dos .conllu.

See b4313a413

arademaker commented 3 years ago

@igorcj, os arquivos JSON do repositório https://github.com/cpdoc/dhbb-ner não estão atualizados. Eles foram gerados para alimentar o demo em http://dhbb.mybluemix.net/dhbb/home, mas as anotações foram feitas com um modelo de reconhecimento de entidades e relações antigo.

Com este comando, produzi os arquivo ner/?.json no 04b8b57f3. Os valores corretos no lugar de APIKEY e URL abaixo não posso publicar, or segurança. Mas o que está sendo feito é passar os arquivos raw para o serviço da IBM chamado natural language understanding e pedindo para ele rodar usando o model treinado no Watson Knowledge Studio.

for f in raw/?.raw; do curl -G --header "Content-Type: application/json" -u 'apikey:APIKEY' --data-urlencode "text@$f" "URL/v1/analyze?version=2020-08-01&features=entities,relations&entities.model=073dab23-dd1e-4ded-badf-f502eb06372c&entities.mentions=true" > ner/$(basename $f .raw).json; done

Então sua tarefa deve ser adaptada para ler este arquivo ner/N.json e alimentar cada sentença no respectivo udp/N.conllu com metadados para as mentions detectadas nos tokens da sentença.

arademaker commented 3 years ago

Vamos ter que usar o método POST para os arquivos maiores, algo como:

curl -X POST --header "Content-Type: application/json" -u 'apikey:KEY' -d @parameters.json "URL/v1/analyze?version=2019-07-12" > ner/1.json

Mas para isso provavelmente será mais fácil usarmos uma biblioteca de http request como http://www.serpentine.com/wreq/tutorial.html para construir o json antes de passar para o serviço.

Em bc9f733e1 removi os arquivos inválidos.

igorcj commented 3 years ago

Revivendo o issue. Trabalhando no repo teste, temos agora um app test-conllu que consegue mergear um .json do diretório ner produzido pelo WKS e um respectivo .conllu do firetório udp produzido pelo UDPipe. Apos mergeeados em um unico .conllu, o mesmo executável é chamado para verifica a consistencia da análise sintática com a identificação das entidades.

Executando esse processo para os arquivos disponíveis, foram reveladas algumas inconsistências, sendo que me parece as mais comuns serem de datas. O que executei foi:

for n in `for f in ner/*.json; do echo $f | awk -F[/.] '{print $2}'; done`; do echo Processando $n; test-conllu -m ner/$n.json udp/$n.conllu temp/$n.conllu; done

Em seguida, para a verificação:

for f in temp/*.conllu; do echo Processando $f; test-conllu -c $f; done > temp/check.log

Onde esse arquivo .log produzido continha a analise de 73 documentos, e inconsistencias foram encontradas em32 deles. Seguem as respectivas entidades:

...

Estou agora analisando mais especificamente os casos para tentar especificar qual ferramenta errou, mas ja temos uma clara divergencia em datas. Coisas como maio do mesmo ano ou agosto de 1966 tem sido marcados como entidades mas não estão contidos em uma subárvore na análise sintática.

arademaker commented 3 years ago
for n in ner/*.json; do echo Processando $n; test-conllu -m $n udp/$(basename $n .json).conllu udp/$(basename $n .json)-n.conllu; done
arademaker commented 3 years ago

Removi o ultimo comentário longo com a lista de todas as entidades.