Sistema de diagnóstico médico experto en Prolog

Entrada


De alguna manera tuve la suerte de elegir el tema de la tesis en ingeniería de software, y elegí escribir un sistema experto, además, en el lenguaje Prolog. Aunque casi nunca se usa en programación industrial, es teóricamente interesante y le permite tocar sistemas inteligentes (IP) de la manera más rápida. Además, el lenguaje en sí es interesante en términos de deportes, ya que te hace pensar de una manera inusual, diferente de pensar en programación de procedimientos y POO, que es un buen entrenamiento para el cerebro.

Utilizamos la implementación de Prolog - Visual Prolog, con bibliotecas GUI incorporadas. Pero si
Si desea escribir una GUI en Qt / C ++, la documentación contiene instrucciones sobre cómo importar un programa en un archivo DLL y compilarlo con un proyecto C / C ++. De ello se deduce que se puede combinar con otros idiomas.

En general, cuando trabajé en este proyecto, no encontré ejemplos que no fueran lo suficientemente primitivos, pero al mismo tiempo no tan grandes como ejemplos científicos sofisticados. Por lo tanto, este artículo puede ser de gran ayuda para principiantes y personas que desean escribir al menos un poco similar a IP.

Descripción del propósito del sistema: hay un conjunto de parámetros a los que debe corresponder la señal cardiosis (ECG), por los cuales se puede determinar la enfermedad. Una persona responde las preguntas del sistema (en modo de diálogo), y el sistema, actuando como experto en enfermedades cardíacas, saca conclusiones sobre una posible enfermedad humana.

Es decir Este código puede considerarse como un marco (prolog-framework) para crear sistemas expertos de otras áreas, simplemente sustituyendo sus propias reglas, sus datos. Las reglas por las cuales se realiza la inserción se describirán a continuación.

Cálculo predicado de primer orden y lenguaje Prolog


El lenguaje Prolog implementa el paradigma de programación lógica, cuya idea es el uso de la tecnología informática para la conclusión lógica de la descripción declarativa del área temática. Esto lo distingue de los lenguajes de programación de procedimientos que describen acciones secuenciales bien definidas. Por lo tanto, los lenguajes de procedimiento no son adecuados para escribir ES, y si se usan, solo como módulos auxiliares. Otra característica distintiva del lenguaje Prolog es el uso de un subconjunto del lenguaje lógico de primer orden para describir un programa, que es conveniente y más simple que para otros; cambia de un lenguaje natural a describir el mundo por una persona. Al crear un ES, este es uno de los problemas importantes: cómo traducir el conocimiento del dominio a un lenguaje formal limitado, mientras se preserva el contenido de información invertido por una persona. También existe una oportunidad simple para transferir el conocimiento de la forma formal a la natural, debido a la comprensibilidad intuitiva y la simplicidad, en comparación con la lógica de segundo orden u otros cálculos matemáticos.

Las construcciones de lenguaje del Prolog se pueden representar en forma de implicaciones de la forma:

A1, A2, …, An <= B1, B2, …,Bm (n>=0, m>=0) (1)

donde Ai y Bi son fórmulas atómicas Fi (t1, t2, ..., tk) o la negación Fi (t1, t2, ..., tk), donde tk son términos (constante individual, variable o resultado de aplicar la función)

En Prolog, todas las relaciones se escriben como hechos y reglas, donde n = 1 en la fórmula (1), para aumentar la eficiencia de la inferencia lógica. Las reglas corresponden a una fórmula llamada fórmula Horn:

A<=B1, B2, …, Bm , m>0 (2)

Los hechos corresponden a la fórmula (2) con m = 0:

A<= (3)

La fórmula que debe probarse en el proceso del mecanismo de inferencia es la fórmula (1) para n = 0, m> 0, llamada meta o solicitud:

<= B1, B2, …Bm (4)

Estas construcciones de lenguaje comprenden todo el programa Prolog.
Por ejemplo, el siguiente conocimiento, en forma de una oración en lenguaje natural - "Son Ani ama a Masha" puede escribirse como un hecho:

 ((), ) 

y la frase "Anya ama a todos los que Olga ama" en la forma:

 ((,X)<=(,X)) 

O el razonamiento “Toda persona es mortal. Confucio es un hombre ”:

 (()& ((X)<=(X)) <= () 

El Prolog también proporciona herramientas para definir estructuras de datos recursivas, como árboles y listas, lo que brinda capacidades adicionales para una descripción conveniente del conocimiento relevante.

Por lo tanto, se puede ver que el Prolog proporciona un lenguaje flexible, simple e intuitivo para describir el conocimiento.

Pero luego surge la pregunta de elegir la implementación de este lenguaje, y se decidió desarrollar ES en la extensión del lenguaje Prolog: Visual Prolog.

Prólogo visual


Visual Prolog es un dialecto del lenguaje Prolog con una extensión orientada a objetos junto con un entorno de desarrollo integrado. Este entorno proporciona soporte para crear interfaces gráficas y muchas otras bibliotecas. El lenguaje Prolog es bastante popular para crear ES, con una sintaxis simple que es similar en significado a las relaciones de dominio y los hechos. En general, el propio intérprete de lenguaje Prolog puede considerarse como un ES en términos de lógica de predicado de primer orden, en la que el usuario hace una pregunta en forma de objetivo, cuya verdad debe demostrarse. Este es un lenguaje declarativo, describe lo que se necesita obtener, en lugar de un algoritmo secuencial, es perfecto para describir el conocimiento de un pequeño ES. En comparación con entornos alternativos, AMZI Prolog y SWI-Prolog proporcionan una interfaz muy efectiva para interactuar con otros idiomas, ya sea al vincular archivos de objetos o al cargar dinámicamente archivos DLL de otros idiomas o como un módulo DLL independiente. Visual Prolog también está bien documentado y tiene muchos ejemplos. También existe la opinión de que la elección de un lenguaje de implementación, una forma de presentar el conocimiento y un método para formar el razonamiento son secundarios, en comparación con el conocimiento de un experto, y afectan solo el mecanismo para su uso exitoso. Sin embargo, la presencia de literatura que usa el prólogo como un medio para crear ES indica la idoneidad de su uso, al menos en sistemas pequeños.

Diseño ES


En la literatura, se acostumbra dividir los ES en varios componentes básicos que dependen poco entre sí: la base de conocimiento, el mecanismo de salida y la interfaz de usuario.

Hay 2 tipos de organización de sistemas expertos: en las reglas y en los hechos.

El conocimiento de ES sobre las reglas se registra en forma de reglas de producción. La parte izquierda de cada regla contiene alguna alternativa para resolver el problema, y ​​las partes correctas (premisas) están especificadas por otras reglas. La única excepción es cuando una regla busca información en la base de datos, como una respuesta a una pregunta. El algoritmo del mecanismo de salida se reduce a comparación, luego, con muchas opciones, se selecciona la que se necesita de acuerdo con el principio de resolución de conflictos y al final se aplica la regla seleccionada y todo comienza de nuevo. Las ventajas de tal organización son que es muy fácil agregar reglas al sistema sin afectar otras reglas, y es fácil de complementar y modificar, ya que el programador solo necesita insertar la regla deseada en el bloque de reglas apropiado. Tal organización también tiene limitaciones, es decir, será necesario organizar un algoritmo antinatural para guardar el rastreo o usar una variable para ello en las reglas, pero esto violará la conveniencia de modificar las reglas, ya que para cada predicado de regla es necesario organizar el guardado de rastreo. Además, esto violará la legibilidad del programa y la posibilidad de modificar el mecanismo de salida en general, ya que junto con la información sobre las reglas, se mantendrá el recorrido por la acción del mecanismo de salida. Además, el Prolog no le permite guardar las reglas en el archivo de la base de datos y leer las reglas de la base de datos, lo que no permitiría actualizar la base de conocimiento mientras se ejecuta el programa. El Listado 1 da un ejemplo de tal organización de base de conocimiento.

Listado 1

 diag("SIRS"):- diag2("SIRS"). diag("Sepsis"):- diag("SIRS"), have("Sepsis character"). diag("Hard sepsis"):- diag("Sepsis"), have("Hard sepsis character"). diag("Shock sepsis"):- diag("Hard sepsis"), have("Shock sepsis character"). diag("MOF"):- diag("Hard sepsis"), have("MOF sepsis character"). diag("MOF"):- diag("Shock sepsis"), have("MOF sepsis character"). 

Como se puede ver en el Listado 1, el mecanismo de salida debería estar completamente controlado por el mecanismo de salida Prolog estándar incorporado.

Los ES organizados según la lógica (sobre los hechos) son más flexibles porque, a diferencia de la conexión directa de las reglas, están organizados según un método de referencia (indirecto) para describir la relación de las reglas. Las relaciones se escriben en términos, como números de reglas, y no reglas anidadas. Tal registro es más consistente con un registro estricto en forma de oraciones de lógica de predicados, lo que hace que el mecanismo para derivar tales reglas sea más flexible. A diferencia de la organización basada en las reglas, la búsqueda de la solución Prolog depende menos del proceso de inferencia lógica de la siguiente regla, ya que es posible realizar otras acciones además de la salida, por ejemplo, pasar por un árbol de decisión alternativo o incluso cambiar el flujo de salida y volver a la posición inicial mientras se mantiene todos los datos al respecto.

Al igual que en la organización, aquí funciona un ciclo sobre las reglas: correspondencia - resolución de conflictos - transición a la siguiente regla, pero dado que el mecanismo de salida se controla indirectamente, es conveniente mostrar información sobre cómo encontrar una solución en el proceso y cambiar este formato sin cambiar la base de conocimiento. La principal ventaja de una organización en la lógica es que es posible hacer que las variables que se asignan durante el proceso de salida estén disponibles automáticamente en el mecanismo de salida, y se pueden mostrar junto con una cadena de las últimas reglas que se envían al objetivo actual. Pero para esto, es necesario proporcionar un mecanismo adicional para los tipos de fantasmas para diferentes tipos de reglas. Además, la base de conocimiento se almacena en forma de hechos, por lo que se puede guardar o leer desde un archivo en el medio. Es más difícil modificar y depurar el sistema en hechos que en reglas, ya que el mecanismo de salida está controlado por los valores de variables y términos, por ejemplo, en forma de un número de regla, que introduce posibilidades adicionales de errores.

También en el mecanismo de salida hay más variables que influyen en este proceso, a veces de tipo recursivo y más bien interconectado, lo que complica el desarrollo y los errores de captura, pero este es el precio por la flexibilidad que proporciona. El sistema también funciona en hechos más eficientemente y más rápido que en las reglas, lo cual es especialmente importante para ES voluminoso en tiempo real, o incluso para ES distribuido en tiempo real.

Un ES grande para el diagnóstico médico en el caso de admisión de pacientes en estado crítico, especialmente si es utilizado simultáneamente por muchos médicos, también debe ajustarse a un marco de tiempo estricto.

Es aún más difícil probar un sistema en hechos debido a su dependencia de los hechos, ya que en un sistema de reglas solo un error afectaría el mecanismo de salida, y esto se haría visible de inmediato, pero lo más probable es que continúe trabajando en hechos.

Como resultado, dado que el sistema desarrollado debe ser informativo para el usuario, es decir, se debe mostrar una respuesta razonable a la pregunta en el proceso de inferencia lógica: por qué el sistema necesitaba la información solicitada para que el usuario sepa en qué etapa de la búsqueda de solución se encuentra, lo que no se puede lograr sin guardar el rastro buscar. También al final, después de responder la pregunta, el usuario debería poder ver el árbol de evidencia de las soluciones encontradas. Dados todos los parámetros del sistema, el sistema más racional me pareció las reglas, ya que puede guardarse en el disco y su mecanismo de salida será más fácil de organizar. Además, el conocimiento sobre el diagnóstico de enfermedades cardiovasculares resultó ser bastante difícil de formalizar debido a su interconexión semántica, especialmente en aquellos lugares donde el significado de las conclusiones de las reglas significaba tener en cuenta información adicional, para cada uno. Por lo tanto, al elegir un mecanismo para intercambiar datos heterogéneos entre predicados, se realizó un cálculo sobre la forma lógica de organización.

También hay 2 tipos de inferencia: inferencia inversa y directa. En los complejos sistemas de consulta médica, todavía se usa una combinación de estos tipos: un tipo deduce una cierta cantidad de conocimiento, y otro ya se usa sobre la base.

Una conclusión directa es encontrar un efecto basado en una multitud de hechos y luego sacar otras conclusiones de las nuevas consecuencias. Es efectivo cuando hay muchas hipótesis conectadas a diferentes niveles que necesitan ser probadas, o cuando hay muchos axiomas para derivar muchas más hipótesis.

La conclusión inversa es la opuesta, primero se selecciona una hipótesis que necesita ser probada, y luego se intenta probar la premisa de esta hipótesis, hasta que la siguiente premisa se encuentre como un axioma.

En ES, el razonamiento sobre las reglas se implementa mediante el método de inferencia lógica inversa, que utiliza Prolog. Se eligió esta opción porque, a diferencia de la inferencia directa, funciona de manera más eficiente con este conocimiento, ya que el número de vértices objetivo es mucho más que hechos y no hay hipótesis en competencia (son independientes).

Implementación


En Prolog, las reglas se implementan como un predicado de regla. Cada regla tiene su propio número y nombre, que es una hipótesis (conclusión) que necesita ser probada. La condición de la regla corresponde a una declaración implícita, que determina completamente la verdad de la hipótesis.

Condición de la regla:

 Colclusion(K)=C1(K) and (C2(K) or C3(K)) and C4(K) 

C1 (K) = Todas las conclusiones de las reglas con números registrados en la primera lista para la regla Kth son verdaderas

C2 (K) = Verdadero, al menos una regla de la segunda lista para la regla K
C3 (K) = Verdaderamente exactamente N (K) Conclusiones de las reglas de la segunda lista para la regla K

C4 (K) = El predicado para la regla Kth (predicado doc (K)), que es descrito por el usuario.
Si alguna lista está vacía, la declaración correspondiente es verdadera.

Al mismo tiempo, se puede ingresar cualquier otro predicado en el predicado para C4, pero al mismo tiempo no deben violar el significado lógico de la conclusión. Para apoyar la negación, algunas conclusiones existentes en la base de conocimiento también se pueden ingresar aquí.

El mecanismo de salida garantiza que las reglas se apliquen en la secuencia correcta y guarda la traza.

El principio principal de la conclusión es probar la verdad de la conclusión, probar consistentemente todas sus conclusiones en la primera lista, luego probar las conclusiones de la segunda lista y al final verificar la verdad del predicado correspondiente al número de la regla actual. Para verificar la segunda lista, si se encuentra al menos una regla verdadera, se verificarán todas las reglas que van al final de la lista.

Descripción del predicado


En general, el principio de codificación del conocimiento se implementa en el Prolog utilizando dos predicados de la siguiente forma:

regla (K, "Texto de conclusión es el nombre de la regla", Id, Lista1, Lista2, N)
doc (K)
K - número de regla
Id: ID de datos para esta regla
Lista1: la primera lista de números de regla
List2 - segunda lista de números de regla
N es el número de conclusiones verdaderas

Además, la regla siempre se escribe como un hecho, sin variables, y su verdad, como se dijo, determina, además de las listas, el documento predicado correspondiente.

Aquí hay algunos ejemplos de conocimiento escrito:

regla (93, “TASH - TASH-score 43%”, tashSc10, [47], [], 0)
regla (33, “TASH - Exceso de motivos - es la suma de puntos”, ninguno, [], [29,30,31,32], 1).

En el documento de predicados, se puede usar cualquier otro predicado, lo que hace posible asignar el texto de la declaración de la regla al conjunto de situaciones que se pueden describir usando el Prólogo.

De esta manera, todo el conocimiento se registra utilizando estos dos predicados.

En los predicados doc, las funciones de la interfaz de usuario se denominan principalmente, ya que algunas reglas están intrínsecamente vinculadas de forma inextricable con la respuesta del usuario o comprueban valores válidos.

Por ejemplo, los predicados doc para reglas cuya verdad depende del intervalo en el que se encuentra la puntuación total hacen las verificaciones adecuadas.

El predicado doc para el diagnóstico de enfermedades de sepsis utiliza el predicado docc adicional, que permite no hacer preguntas innecesarias al usuario. Por ejemplo, si un signo requiere al menos dos signos, si la respuesta es no a dos signos, el sistema no debería hacer más preguntas, ya que es obvio que el signo no puede ser verdadero. Para hacer esto, el predicado docc proporciona una verificación de más de dos respuestas negativas en la base de datos. Tampoco tiene sentido hacer la tercera pregunta si ya hay una respuesta a dos preguntas suficientes para establecer la verdad de la característica resultante.

El predicado kolNeg (Cantidad) busca el número de respuestas negativas en la base de datos para este grupo de atributos. Para hacer esto, primero busca todo tipo de signos de este grupo de signos para no confundirlos con otros grupos, y luego los considera del conjunto en la base de datos usando el predicado kol_neg_list_in_db trabajando con la lista de signos de este grupo.

Ejemplos de código


El proyecto es grande, por lo que daré los pasajes más importantes.

Listado 2 - Lista de reglas

 rule(11,"Sepsises - SIRS . 1: t>38C  t<36",sirsPr1,[],[],0). rule(12,"Sepsises -   >90",sirsPr2,[],[],0). rule(13,"Sepsises -  >20  PaCO2<32mmHg",sirsPr3,[],[],0). 

Listado 3 - Lista de hechos

 fact1(sirsPr1,"SIRS","SIRS . 1: t>38C  t<36"). fact1(sirsPr2,"SIRS","  >90"). fact1(sirsPr3,"SIRS"," >20  PaCO2<32mmHg"). fact1(sirsPr4,"SIRS","- >12.000/mm>3, <4.000/mm>3  >10% band"). 

- Lista de consecuencias lógicas.

 tash_score(1,tashSc1,0,8,"  <5%"). tash_score(2,tashSc2,9,9,"  6%"). tash_score(3,tashSc3,10,10,"  8%"). 

Listado 4 - Máquina de salida

 sizeList([],0):-!. sizeList([_|T],Size):- sizeList(T,SizeTail), Size=SizeTail+1. append_der_list([],List,List). append_der_list([H|L1],List2,[H|L3]):- append_der_list(L1,List2,L3). any2(NeedSize,NeedSize,_,[],[],_):-!. any2(_,_,[],[],[],_):-!. any2(NeedSize,Size,[H|T1],[H|T2],[FirstDer|OtherDer],Why):- Nomer=[H], go(Nomer,UnderFirstDer,Why), rule(H,Text,_,_,_,_), FirstDer=tree(Text,unmarked,UnderFirstDer,0),%der(H,UnderFirstDer), Size1=Size+1,!, any2(NeedSize,Size1,T1,T2,OtherDer,Why). any2(NeedSize,Size,[_|T1],List,OrDer,Why):- !,any2(NeedSize,Size,T1,List,OrDer,Why). go([],[],_):-!. go([H|T],[FirstDer|OtherDer],Why):- rule(H,Name,_,ListAnd,ListOr,KolOr), NewWhy=[Name|Why], go(ListAnd,UnderFirstDer,NewWhy), goOr(ListOr,KolOr,_,OrDer,NewWhy), append_der_list(UnderFirstDer,OrDer,TwoDers), FirstDer=tree(Name,unmarked,TwoDers,0), asserta(why_trace(NewWhy)), doc(H,NewWhy), go(T,OtherDer,Why). goOr([],_,[],[],_):-!. goOr(ListOr,KolOr,ListYes,OrDer,Why):- KolOr<>0, any2(KolOr,0,ListOr,ListYes,OrDer,Why), sizeList(ListYes,KolOr). goOr(ListOr,0,ListYes,OrDer,Why):- any2(100000,0,ListOr,ListYes,OrDer,Why), sizeList(ListYes,KolListYes), KolListYes>0. 

Listado 5 - conclusión de las consecuencias finales

 tashQuestion(Id):- fact2(Id,_,Prisnak,_), pos(Prisnak),!. tashQuestion(Id):- fact2(Id,_,Prisnak,_), neg(Prisnak),fail,!. tashQuestion(Id):- fact2(Id,_,Prisnak,Ball), not(neg(Prisnak)), not(pos(Prisnak)), dialog_ynw(Prisnak,Ans), tash_in_data_base(Ans,Prisnak,Ball),!. tash_in_data_base("y",Prisnak,Ball):- asserta(pos(Prisnak)),sum_tash(Sum1),Sum2=Sum1+Ball,asserta(sum_tash(Sum2)),!. tash_in_data_base("n",Prisnak,_):- asserta(neg(Prisnak)),!,fail. tash_in_data_base(_,_,_):- write("\nTASH-not correct answer"),!,fail. oneQuestion(Id):- fact1(Id,_,Prisnak), pos(Prisnak),!. oneQuestion(Id):- fact1(Id,_,Prisnak), not(neg(Prisnak)), question_sepsis(Prisnak),!. 

Conclusiones


Espero que este artículo ayude a los principiantes a construir su propio sistema experto.

Source: https://habr.com/ru/post/es436722/


All Articles