A ideia
Já estamos em 2024, a versão IRIS 2024.1 acabou de ser lançada e todo mundo está falando sobre ela por aqui. Já temos muitos tutoriais sobre busca vetorial e aplicações de chat de inteligência artificial. Hoje quero propor algo diferente. Quero apresentar uma ideia e explorar todos os seus limites, e ao longo do texto farei algumas perguntas sobre a capacidade das ferramentas utilizadas, para que depois possamos compreender não só os resultados das novas funcionalidades, mas também como a máquina as processa.
A ideia é simples: transformar as anamneses psicológicas dos pacientes em vetores e utilizá-los como base para a aprendizagem de máquina. Dessa forma, podemos construir uma máquina capaz de discernir se um paciente tem um diagnóstico a partir de sua anamnese.
Para começar, vamos testar com exemplos de anamneses de pacientes autistas e não autistas e criar um banco de dados de vetores para treiná-lo a distinguir os pacientes com transtorno do espectro autista daqueles que não o têm.
Para isso necessitaremos:
- Uma base de dados de anamneses de pacientes com e sem o transtorno (já existem alguns casos disponíveis na internet, e podemos até gerá-los nós mesmos com a ajuda da IA Google Gemini).
-Um modelo de incorporação em Python para transformar anamneses em vetores;
- InterSystems Machine Learning.
O objetivo aqui não é substituir um terapeuta ou psicólogo, mas discutir o poder e os limites das ferramentas InterSystems. E se fizermos bem, essa aplicação pode se tornar um acessório para esses profissionais.
Passo a passo
1- Transformar o texto em vetores
Primero temos que aprender como fazer a transformação de texto cru para vetores.
Seguindo o tutorial da documentação InterSystems, devemos escolher um módulo Python que tenha um bom modelo para o tipo de texto que vamos transformar.
Além da sugestão da documentação, quero adicionar a sugestão de usar a função Word2Vec da biblioteca Gensim, como no código abaixo. Deixo também dois sites que a explicam como um mestre: Text Vectorization Using Python: Word2Vec e Word2Vec — Skip-Gram (esse último é mais por curiosidade, achei muito interessante).
import gensim
from gensim.models import Word2Vec, KeyedVectors
import pandas as pd
import re
def remove_prepositions(text):
prepositions = ['his', 'he', 'she', 'her', 'hers','it','about', 'above', 'across', 'after', 'against', 'along', 'among', 'around', 'at', 'before', 'behind', 'below', 'beneath', 'beside', 'between', 'beyond', 'but', 'by', 'concerning', 'considering', 'despite', 'down', 'during', 'except', 'for', 'from', 'in', 'inside', 'into', 'like', 'near', 'of', 'off', 'on', 'onto', 'out', 'outside', 'over', 'past', 'regarding', 'round', 'since', 'through', 'throughout', 'till', 'to', 'toward', 'under', 'underneath', 'until', 'up', 'upon', 'with', 'within', 'without']
pattern = r'\b(' + '|'.join(prepositions) + r')\b\s*'
text = re.sub(pattern, '', text, flags=re.IGNORECASE)
return text
with open('./texts/tea-adult.txt', 'r') as f:
f = remove_prepositions(f.read())
lines = f.split('\n')
data = pd.DataFrame(list(zip(lines)))
data.columns = ['anamnesis']
anamnesis_new=data.anamnesis.apply(gensim.utils.simple_preprocess)
model=gensim.models.Word2Vec(window=5, min_count=2, workers=4, sg=0)
model.build_vocab(anamnesis_new, progress_per=1000)
model.train(anamnesis_new, total_examples=model.corpus_count, epochs=model.epochs)
model.save("./anamnesis.model")
Eu escolhi tratar o texto nesse caso usando uma simples função que encontrei em uma busca rápida, porque se retirarmos preposições e outras palavras que não têm relação com assuntos específicos, resulta em uma melhor performance e rendimento da máquina. Isso porque assim o texto é menor.
Aqui deixo minhas primeiras perguntas:
- É melhor pré-processar o texto eliminando preposições e outras palavras irrelevantes antes de transformá-lo em vetores?
- Uma máquina não tem o conceito de semântica. Assim, essa manobra pressupõe que não há perda de significado para o computador. Essa suposição é enganosa?
Criar a base de dados com os vetores em IRIS
Não quero ocupar muito do seu tempo aqui, pois a documentação InterSystems já explicou essa parte muito bem.
Resumindo, temos que criar uma tabela com uma coluna para os embeddings e um UID que faça referência ao texto original. Aí, adicionamos cada incorporação texto-vetor e seu UID na tabela:
INSERT INTO Sample.Embeddings (Embedding, UID)
VALUES (TO_VECTOR(?,double), ?)
Se você escolher usar o Word2Vec, a lista de embeddings pode ser extraída do modelo salvo em "./anamnesis.model" no exemplo acima.
Outra pergunta: o que você usou para transformar os textos em vetores? Por que escolheu esse método?
Usar o InterSystems IRIS ML para treinar a tabela
Agora que temos a tabela com os vetores, podemos adicionar uma coluna que indica se a incorporação veio de uma anamnese de um autista ou não.
Seguindo novamente a excelente documentação da InterSystems sobre esse assunto, criamos um modelo de predição a partir dessa tabela.
CREATE MODEL AnamnesiaAutistaModel PREDICTING (es_autista) FROM AnamnesiaAutista
A treinamos
TRAIN MODEL AnamnesiaAutistaModel
E a validamos com algumas anamneses que ainda não usamos.
VALIDATE MODEL AnamnesiaAutistaModelo From AnamnesiaTeste
Por fim, podemos fazer a predição em novos dados.
SELECT *, PREDICT(AnamnesiaAutistaModel) FROM NuevasAnamnesias
Análise matemática da solução
Solução 1: Utilizando o InterSystems IntegratedML para realizar todas as etapas descritas anteriormente, aplicamos um modelo de floresta aleatória para decidir se um teste de autismo é positivo ou negativo, com base no conhecimento fornecido ao computador. Obviamente, com a colaboração de um psicólogo no projeto, podemos adicionar, além das anamneses, uma lista de sintomas de autismo e treinar ainda mais a máquina para obter resultados melhores.
Dessa forma, o computador toma uma decisão com base em números que representam medidas de relação entre palavras. Se essa relação for similar à dos dados utilizados para treinar a máquina, ela decide que o diagnóstico é positivo. Acredito que podemos melhorar os resultados se atribuirmos pesos a essas medidas, de acordo com sua relação com a palavra "autismo". Podemos alcançar isso combinando a ferramenta com a busca vetorial antes da tomada de decisão da máquina. Seguindo o exemplo com Gensim:
similarity = model.wv.similarity(w1='autism',w2='sociability')
Então, se o computador decidir por sim, mas essa semelhança for baixa, a decisão será negativa.
Solução 2: Outra opção era simplesmente realizar uma busca vetorial em nossa tabela de incorporações. Lá teríamos usado uma similaridade de cosseno ou produto escalar e chegado a uma similaridade suficiente (algo como um valor p de 0,05) que nos diria se é um caso de autismo ou não.
Assim, temos as duas perguntas finais:
- Para um modelo de aprendizado de máquina, o benefício de usar um vetor no lugar de um texto é óbvio em termos de desempenho, pois estamos usando números, que são mais próximos da linguagem da máquina, então pulamos algumas etapas que a máquina teria que fazer. Mas o resultado é igualmente bom?
- Se os resultados nas duas soluções forem próximos, a busca vetorial pode ser usada como base para aprendizado de máquina e predição? Em quais casos é mais adequado utilizar um enfoque ou outro?
O Futuro
Um banco de dados com essas características também pode ser utilizado para pesquisas e descoberta de novas similaridades em diversos tipos de diagnósticos. Ao adicionar detalhes sobre o estilo de vida dos pacientes, além dos sintomas, a máquina pode realizar uma análise pragmática e gerar novas hipóteses para pesquisa, permitindo confirmar se a máquina interpretou corretamente as relações entre comportamentos e diagnósticos.