Système expert médical de diagnostic sur Prolog

Entrée


D'une certaine manière, j'ai eu la chance de choisir le sujet de la thèse en génie logiciel, et j'ai choisi d'écrire un système expert, en plus, en langage Prolog. Bien qu'il ne soit presque jamais utilisé en programmation industrielle, il est théoriquement intéressant et permet de toucher les systèmes intelligents (IP) de la manière la plus rapide. De plus, le langage lui-même est intéressant en termes de sport, car il vous fait penser d'une manière inhabituelle, différente de la pensée de la programmation procédurale et de la POO, qui est un bon entraînement pour le cerveau.

Nous avons utilisé l'implémentation de Prolog - Visual Prolog, avec des bibliothèques GUI intégrées. Mais si
Si vous souhaitez écrire une interface graphique dans Qt / C ++, la documentation contient des instructions sur la façon d'importer un programme dans une DLL et de le compiler avec un projet C / C ++. Il s'ensuit qu'il peut être combiné avec d'autres langues.

En général, lorsque j'ai travaillé sur ce projet, je n'ai pas trouvé d'exemples qui n'étaient pas assez primitifs, mais en même temps pas aussi gros que des exemples scientifiques sophistiqués. Par conséquent, cet article peut être très utile pour les débutants et les personnes qui souhaitent écrire au moins un peu comme IP.

Description de l'objectif du système: il existe un ensemble de paramètres auxquels un cardiosignal (ECG) doit correspondre, en fonction desquels vous pouvez déterminer la maladie. Une personne répond aux questions du système (en mode dialogue) et le système, agissant en tant qu'expert des maladies cardiaques, tire des conclusions sur une maladie humaine potentielle.

C'est-à-dire Ce code peut être considéré comme un framework (prolog-framework) pour créer des systèmes experts à partir d'autres domaines, simplement en substituant vos propres règles, vos données. Les règles selon lesquelles l'insertion est effectuée seront décrites ci-dessous.

Calcul des prédicats de premier ordre et langage Prolog


Le langage Prolog met en œuvre le paradigme de programmation logique, dont l'idée est l'utilisation de la technologie informatique pour la conclusion logique de la description déclarative du domaine. Cela le distingue des langages de programmation procéduraux qui décrivent des actions séquentielles bien définies. Par conséquent, les langages procéduraux ne conviennent pas à l'écriture d'ES, et s'ils sont utilisés, alors uniquement comme modules auxiliaires. Une autre caractéristique distinctive du langage Prolog est l'utilisation d'un sous-ensemble du langage logique de premier ordre pour décrire un programme, ce qui est pratique et plus simple que pour les autres; il passe d'un langage naturel à la description du monde par une personne. Lors de la création d'un ES, c'est l'un des problèmes importants - comment traduire les connaissances du domaine dans un langage formel limité, tout en préservant le contenu informationnel investi par une personne. Il existe également une occasion simple de retransférer les connaissances de la forme formelle à la forme naturelle, en raison de la compréhensibilité et de la simplicité intuitives, par rapport à la logique du second ordre ou à d'autres calculs mathématiques.

Les constructions linguistiques du Prolog peuvent être représentées sous la forme d'implications de la forme:

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

où Ai et Bi sont des formules atomiques Fi (t1, t2, ..., tk) ou la négation Fi (t1, t2, ..., tk), où tk sont des termes (constante individuelle, variable ou résultat de l'application de la fonction)

Dans Prolog, toutes les relations sont écrites sous forme de faits et de règles, où n = 1 dans la formule (1), pour augmenter l'efficacité de l'inférence logique. Les règles correspondent à une formule appelée formule Horn:

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

Les faits correspondent à la formule (2) avec m = 0:

A<= (3)

La formule qui doit être prouvée dans le processus du mécanisme d'inférence est la formule (1) pour n = 0, m> 0, appelée objectif ou demande:

<= B1, B2, …Bm (4)

Ces constructions de langage comprennent l'ensemble du programme Prolog.
Par exemple, les connaissances suivantes, sous la forme d'une phrase en langage naturel - «Son Ani aime Masha» peuvent être écrites comme un fait:

 ((), ) 

et la phrase «Anya aime tous ceux que Olga aime» sous la forme:

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

Ou le raisonnement «Chaque personne est mortelle. Confucius est un homme »:

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

Le Prolog fournit également des outils pour définir des structures de données récursives, telles que des arbres et des listes, ce qui apporte des capacités supplémentaires pour une description pratique des connaissances pertinentes.

Ainsi, on peut voir que le Prolog fournit un langage flexible, simple et intuitif pour décrire les connaissances.

Mais alors la question se pose de choisir l'implémentation de ce langage, et il a été décidé de développer ES sur l'extension du langage Prolog - Visual Prolog.

Prologue visuel


Visual Prolog est un dialecte du langage Prolog avec une extension orientée objet et un environnement de développement intégré. Cet environnement prend en charge la création d'interfaces graphiques et de nombreuses autres bibliothèques. Le langage Prolog est assez populaire pour créer des ES, avec une syntaxe simple qui a une signification similaire aux relations et aux faits de domaine. En général, l'interprète de langage Prolog lui-même peut être considéré comme un ES en termes de logique de prédicat de premier ordre, dans laquelle l'utilisateur pose une question sous la forme d'un objectif dont la vérité doit être prouvée. Il s'agit d'un langage déclaratif, il décrit ce qui doit être obtenu, au lieu d'un algorithme séquentiel, est parfait pour décrire la connaissance d'un petit ES. Par rapport aux environnements alternatifs, AMZI Prolog et SWI-Prolog fournissent une interface très efficace pour interagir avec d'autres langues, soit en liant des fichiers objets soit en chargeant dynamiquement des DLL d'autres langues ou en tant que module DLL autonome. Visual Prolog est également bien documenté et contient de nombreux exemples. Il existe également une opinion selon laquelle le choix d'un langage de mise en œuvre, une manière de présenter les connaissances et une méthode de formation du raisonnement sont secondaires, par rapport aux connaissances d'un expert, et n'affectent que le mécanisme de leur utilisation réussie. Néanmoins, la présence d'une littérature utilisant le prologue comme moyen de créer des ES indique la pertinence de son utilisation, au moins dans les petits systèmes.

Conception ES


Dans la littérature, il est habituel de diviser les ES en plusieurs composants de base peu dépendants les uns des autres: la base de connaissances, le mécanisme de sortie et l'interface utilisateur.

Il existe 2 types d'organisation des systèmes experts: sur les règles et sur les faits.

La connaissance d'ES sur les règles est enregistrée sous forme de règles de production. La partie gauche de chaque règle contient une alternative à la résolution du problème, et les parties droites (prémisses) sont spécifiées par d'autres règles. La seule exception est lorsqu'une règle recherche des informations dans la base de données, comme une réponse à une question. L'algorithme du mécanisme de sortie est réduit à la comparaison, puis avec de nombreuses options, celle qui est nécessaire est sélectionnée conformément au principe de résolution des conflits et à la fin la règle sélectionnée est appliquée et tout recommence. Les avantages d'une telle organisation sont qu'il est très facile d'ajouter des règles au système sans affecter d'autres règles, et il est facile de compléter et de modifier, car le programmeur n'a qu'à insérer la règle souhaitée dans le bloc de règles approprié. Une telle organisation a également des limites, à savoir, il sera nécessaire d'organiser un algorithme non naturel pour enregistrer la trace ou d'utiliser une variable pour celle-ci dans les règles, mais cela violera la commodité de modifier les règles, car pour chaque prédicat de règle, il est nécessaire d'organiser l'enregistrement de la trace. En outre, cela violera la lisibilité du programme et la possibilité de modifier le mécanisme de sortie en général, car avec les informations sur les règles, la traversée par l'action du mécanisme de sortie sera conservée. En outre, le prologue ne vous permet pas d'enregistrer les règles dans le fichier de base de données et de lire les règles de la base de données, ce qui ne permettrait pas de mettre à jour la base de connaissances pendant l'exécution du programme. Le listing 1 donne un exemple d'une telle organisation de base de connaissances.

Listing 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"). 

Comme le montre le Listing 1, le mécanisme de sortie doit être complètement contrôlé par le mécanisme de sortie standard Prolog intégré.

Les ES organisés sur la logique (sur les faits) sont plus flexibles, car, contrairement à la connexion directe des règles, ils sont organisés sur une méthode de référence (indirecte) pour décrire la relation des règles. Les relations sont écrites en termes, tels que des numéros de règles, et non des règles imbriquées. Un tel enregistrement est plus cohérent avec un enregistrement strict sous la forme de phrases de logique de prédicat, ce qui rend le mécanisme pour dériver de telles règles plus flexible. Contrairement à l'organisation basée sur les règles, la recherche de la solution Prolog dépend moins du processus d'inférence logique de la règle suivante, car il devient possible d'effectuer d'autres actions en plus de la sortie, par exemple, passer par un autre arbre de décision ou même changer le flux de sortie et revenir à la position de départ tout en maintenant toutes les données à ce sujet.

Comme dans l'organisation, un cycle opère sur les règles ici: correspondance - résolution des conflits - transition vers la règle suivante, mais comme le mécanisme de sortie est contrôlé indirectement, il est pratique d'afficher des informations sur la recherche d'une solution dans le processus et de changer ce format sans changer la base de connaissances. Le principal avantage d'une organisation sur la logique est qu'il est possible de rendre les variables mappées pendant le processus de sortie automatiquement disponibles dans le mécanisme de sortie, et qu'elles peuvent être affichées avec une chaîne des dernières règles qui sont sorties vers la cible actuelle. Mais pour cela, il est nécessaire de prévoir en plus un mécanisme pour les types fantômes pour différents types de règles. De plus, la base de connaissances est stockée sous forme de faits, elle peut donc être enregistrée ou lue à partir d'un fichier sur le support. Il est plus difficile de modifier et de déboguer le système sur des faits que sur des règles, car le mécanisme de sortie est contrôlé par les valeurs des variables et des termes, par exemple sous la forme d'un numéro de règle, ce qui introduit des possibilités supplémentaires d'erreurs.

Dans le mécanisme de sortie, il y a également plus de variables qui influencent ce processus, parfois de type récursif et plutôt interconnectées, ce qui complique le développement et les erreurs de capture, mais c'est le prix de la flexibilité qu'il offre. Le système fonctionne également plus efficacement et plus rapidement sur les faits que sur les règles, ce qui est particulièrement important pour les ES en temps réel volumineux, ou même pour les ES en temps réel distribués.

Un ES important pour le diagnostic médical en cas d'admission de patients dans un état critique, en particulier s'il est utilisé simultanément par de nombreux médecins, doit également s'inscrire dans un délai strict.

Il est encore plus difficile de tester un système sur des faits en raison de sa dépendance à l'égard des faits, car dans un système sur des règles, seule une erreur affecterait le mécanisme de sortie, et cela deviendrait immédiatement visible, mais très probablement, il continuerait de fonctionner sur des faits.

En conséquence, étant donné que le système développé doit être informatif pour l'utilisateur, à savoir, une réponse raisonnée à la question doit être affichée dans le processus d'inférence logique - pourquoi le système a-t-il besoin des informations demandées pour que l'utilisateur sache à quel stade de la recherche de solutions il se trouve, ce qui ne peut être réalisé sans enregistrer la trace recherche. Toujours à la fin, après avoir répondu à la question, l'utilisateur devrait pouvoir voir l'arborescence des preuves des solutions trouvées. Compte tenu de tous les paramètres du système, le système le plus rationnel m'a semblé les règles, car il peut être enregistré sur disque et son mécanisme de sortie sera plus facile à organiser. De plus, les connaissances sur le diagnostic des maladies cardiovasculaires se sont révélées assez difficiles à formaliser en raison de leur interconnexion sémantique, en particulier dans les endroits où la signification des conclusions des règles impliquait de prendre en compte des informations supplémentaires, pour chacune la sienne. Par conséquent, lors du choix d'un mécanisme d'échange de données hétérogènes entre prédicats, un calcul a été effectué sur la manière logique d'organiser.

Il existe également 2 types d'inférence: l'inférence inverse et l'inférence directe. Dans les systèmes de consultation médicale complexes, une combinaison de ces types est toujours utilisée: une certaine quantité de connaissances est déduite par un type, et un autre est déjà utilisé sur sa base.

Une conclusion directe est de trouver un effet basé sur une multitude de faits, puis de tirer d'autres conclusions des nouvelles conséquences. Il est efficace lorsqu'il existe de nombreuses hypothèses liées à différents niveaux qui doivent être prouvées, ou lorsque de nombreux axiomes permettent de dériver de nombreuses autres hypothèses.

La conclusion inverse est l'inverse, d'abord une hypothèse est sélectionnée qui doit être prouvée, puis une tentative est faite pour prouver la prémisse de cette hypothèse, jusqu'à ce que la prémisse suivante soit trouvée comme un axiome.

Dans ES, le raisonnement sur les règles est implémenté par la méthode d'inférence logique inverse, qui utilise Prolog. Cette option a été choisie, car, contrairement à l'inférence directe, elle fonctionne plus efficacement avec cette connaissance, car le nombre de sommets cibles est beaucoup plus que les faits et il n'y a pas d'hypothèses concurrentes (elles sont indépendantes).

Implémentation


Dans Prolog, les règles sont implémentées en tant que prédicat de règle. Chaque règle a son propre numéro et nom, ce qui est une hypothèse (conclusion) qui doit être prouvée. La condition de la règle correspond à un énoncé implicite, qui détermine complètement la vérité de l'hypothèse.

Condition de la règle:

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

C1 (K) = Toutes les conclusions des règles avec des nombres enregistrés dans la première liste pour la Kème règle sont vraies

C2 (K) = Vrai, au moins une règle de la deuxième liste pour la Kème règle
C3 (K) = Vraiment exactement N (K) Conclusions des règles de la deuxième liste pour la Kème règle

C4 (K) = Prédicat de la règle Kth (doc prédicat (K)), qui est décrit par l'utilisateur.
Si une liste est vide, la déclaration correspondante est vraie.

En même temps, tout autre prédicat peut être entré dans le prédicat pour C4, mais en même temps, il ne doit pas violer le sens logique de la conclusion. Pour soutenir le refus, certaines conclusions existantes dans la base de connaissances peuvent également être saisies ici.

Le mécanisme de sortie garantit que les règles sont appliquées dans le bon ordre et enregistre la trace.

Le principe principal de la conclusion est de prouver la vérité de la conclusion, de prouver systématiquement toutes ses conclusions dans la première liste, puis de prouver les conclusions de la deuxième liste et au final de vérifier la vérité du prédicat correspondant au numéro de la règle courante. Pour vérifier la deuxième liste, si au moins une vraie règle est trouvée, toutes les autres règles en cours à la fin de la liste seront vérifiées.

Description du prédicat


En général, le principe du codage des connaissances est implémenté sur le Prolog à l'aide de deux prédicats sous la forme suivante:

règle (K, "Le texte de conclusion est le nom de la règle", Id, List1, List2, N)
doc (K)
K - numéro de règle
Id - ID de données pour cette règle
List1 - la première liste de numéros de règle
List2 - deuxième liste de numéros de règle
N est le nombre de vraies conclusions

De plus, la règle est toujours écrite comme un fait, sans variables, et sa vérité, comme on l'a dit, détermine, en plus des listes, le doc prédicat correspondant.

Voici quelques exemples de connaissances en écriture:

règle (93, «TASH - TASH-score 43%», tashSc10, [47], [], 0)
règle (33, «TASH - Excess of motifs - is the sum of points», none, [], [29,30,31,32], 1).

Dans le doc prédicat, tout autre prédicat peut être utilisé, ce qui permet de mapper le texte de l'énoncé de la règle à l'ensemble des situations qui peuvent être décrites à l'aide du Prolog.

De cette façon, toutes les connaissances sont enregistrées à l'aide de ces deux prédicats.

Dans les prédicats doc, les fonctions de l'interface utilisateur sont principalement appelées, car certaines règles sont intrinsèquement inextricablement liées à la réponse de l'utilisateur ou vérifient les valeurs valides.

Par exemple, le doc prédicte les règles dont la vérité dépend de l'intervalle dans lequel se situe le score total, effectuez les vérifications appropriées.

Le prédicat doc pour le diagnostic des maladies septiques utilise le prédicat docc supplémentaire, qui permet de ne pas poser de questions inutiles à l'utilisateur. Par exemple, si un signe nécessite au moins deux signes, si la réponse est non à deux signes, le système ne devrait pas poser plus de questions, car il est évident que le signe ne peut pas être vrai. Pour ce faire, le prédicat docc vérifie plus de deux réponses négatives dans la base de données. Il est également insensé de poser la troisième question s'il existe déjà une réponse à deux questions suffisantes pour établir la vérité de la caractéristique résultante.

Le prédicat kolNeg (Quantity) recherche le nombre de réponses négatives dans la base de données pour un groupe d'attributs donné. Pour ce faire, il recherche d'abord toutes sortes de signes de ce groupe de signes afin de ne pas les confondre avec d'autres groupes, puis les considère dans l'ensemble de la base de données en utilisant le prédicat kol_neg_list_in_db travaillant avec la liste des signes de ce groupe.

Exemples de code


Le projet est vaste, je vais donc donner les passages les plus importants.

Listing 2 - Liste des règles

 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). 

Listing 3 - Liste des faits

 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"). 

- Liste des conséquences logiques

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

Listing 4 - Machine de sortie

 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. 

Listing 5 - Conclusion des conséquences 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),!. 

Conclusions


J'espère que cet article aide les débutants à construire leur propre système expert.

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


All Articles