IA

L’intelligence arificielle (IA) est une discipline scientifique qui a vu officiellement le jour en 1956.

Elle repose sur la conjecture selon laquelle toutes les fonctions cognitives, en particulier l’apprentissage, le raisonnement, le calcul,
la perception, la mémorisation, voire la découverte scientifique ou la créativité artistique, peuvent
être reproduites sur des ordinateurs.

L’apprentissage automatique (Machine Learning) est à l’intersection de l’IA et d’un autre champ scientifique : la science des données (data science).

En pratique, il s’agit de produire des réponses adaptées aux données fournies en entrée (identifier des motifs, des tendances, construire des modèles, faire des prédictions).

L’apprentissage automatique n’est donc ni plus ni moins que du traitement de données visant à prédire des résultats en fonction
des données entrantes.


Exemple d’apprentissage supervisé :

Algorithme des K
plus proches voisins

KNN est un algorithme d’apprentissage supervisé cela signifie que l’algorithme nécessite
des données classifiées en amont qui vont lui servir à trouver la bonne étiquette pour
d’autres données non encore classifiées.

Suivant la nature de l’étiquette, KNN peut servir à :

  • une classification des nouvelles données
    si les étiquettes sont des catagories ;
  • une régression si les étiquettes
    sont des nombres.

KNN enregistre, dans un premier temps, tous les points de données étiquetées qui vont lui servir à l’apprentissage (c’est le training set).

Puis, quand arrive un point de donnée non étiqueté, l’algorithme calcule sa distance aux autres points et sélectionne les k plus proches.

On a alors deux cas possibles :

  • si les étiquettes sont des catégories, l’algorithme calcule le mode des catégories des voisins sélectionnés (catégorie la plus représentée).

  • si les étiquettes sont des nombres, l’algorithme calcule la moyenne des étiquettes des voisins sélectionnés.

Dans l’animation suivante, on utilise KNN pour répondre à la question suivante :

Quelle est la couleur du nouveau point ?

L’algorithme des k plus proches voisins
est non paramétrique.

Aucun modèle mathématique de classification ou régression n’est construit à partir des données
(pas de paramètre à ajuster).

Les données d’apprentissage
sont enregistrées telles quelles.

Cela signifie qu’on ne présuppose rien de particulier sur les données (à part que des points proches appartiennent à la même catégorie).

L’algorithme est donc particulièrement
robuste (les données parlent d’elles-même)
et simple à mettre à jour (suffit d’ajouter
les nouvelles données d’apprentissage).

Le choix de k modifie le résultat obtenu.

  • Si k est trop petit, le moyennage est faible et donc la variabilité va être très grande. On parle alors de surapprentissage (overfitting).
  • En augmentant k, les résultats obtenus se stabilisent (vote de la majorité) et les erreurs diminuent, jusqu’au moment où la boule à l’intérieur de laquelle se fait le moyennage devient trop grosse, amenant in fine l’algorithme a choisir systématiquement la catégorie majoritaire, quel que soit le point… On augmente alors le biais (ici, le biais est le préjudice en faveur du plus grand nombre). L’ajustement ne suit plus les variations, on parle de sous-apprentissage (underfitting).

Le choix de k est donc affaire de compromis. Pour le rendre plus scientifique, on peut chercher à mesurer la performance de l’algorithme pour différentes valeurs de k.

Mais comment mesure-t-on la performance d’un algorithme d’apprentissage automatique ?

La matrice de confusion permet d’évaluer
la qualité des prédictions d’un algorithme.

Utilisons KNN sur une banque d’images de chiffres écrits à la main et concentrons-nous sur
sa capacité à reconnaître des “3”.

Un algorithme peut très bien être très précis
(les prédictions positives sont bien des 3),
mais peu sensible, avec un faible taux de rappel (parmi tous les 3, peu ont été identifiés).

À l’inverse, on peut avoir une bonne sensibilité
(la plupart des vrais 3 ont été identifiés comme tel), mais peu précis (beaucoup de chiffres identifiés comme des 3 sont en fait d’autres chiffres).

Exemple d’apprentissage non-supervisé :

Algorithme des
K-moyennes

L’algorithme des k-moyennes regroupe
en catégories des données
dont on ne connaît rien a priori.


C’est un algorithme
de partitionnement
des données (clustering).

L’algorithme depend d’un seul paramètre
(en plus des données) :
le nombre de partitions k.

  • On commence par choisir k points au hasard dans l’espace des données (il peut s’agir de k points de données ou de k autres points). Ce sont les k centres (ou centroïdes).

  • On attribue ensuite à chaque centre tous les points de données qui lui sont le plus proches, formant ainsi k groupes.

  • Enfin, on déplace chaque centre au barycentre de son groupe.

On répète les deux dernières opérations (attribution des points les plus près
et déplacement des centres)
tant que les centres bougent
d’une itération à l’autre.

L’algorithme vise à résoudre au final un problème d’optimisation ; son but est en effet de trouver le minimum de la distance entre les points à l’intérieur de chaque partition.

Mathématiquement, étant donné un ensemble
de points $(x_1,x_2,\ldots,x_n)$, on cherche à partitionner les $n$ points en $k$ ensembles $S=\{S_1,S_2,\ldots,S_k\}$ en minimisant la grandeur $$I = \sum_{i=1}^{k}\sum_{x_j \in S_i}||x_i-\mu_i||^2$$ où $\mu_i$ est le barycentre des points dans $S_i$.

$I$ est la variance intra-classe ou inertie intra-classe (terme surtout utilisé en anglais).

Choix de k

Limites

Jeux d’accessibilité
sur un graphe

On quitte l’apprentissage automatique
mais on reste dans le champ de l’IA.

Vocabulaire

On entendra ici par jeu :

  • des jeux à deux joueurs
    ($J_1$ et $J_2$ ou Eve et Adam)
  • à information complète : les deux joueurs savent tout (pas comme aux cartes)
  • alternés (pas comme à chifoumi)
  • non randomisés (pas de hasard)

L’arène dans laquelle le jeu prend place
est un graphe orienté biparti.

Un graphe biparti (ou bipartite) $G$ est un graphe dont l'ensemble des sommets peut être divisé en deux sous-ensembles de sommets disjoints $S_1$ et $S_2$ ($S_1$ et $S_2$ sont une partition de $S$ : $S_1\cup S_2=S$, $S_1\cap S_2=\varnothing$) tels que chaque arête de $G$ a une extrémité dans $S_1$ et l'autre dans $S_2$.

Deux joueurs, $J_1$ et $J_2$, s’affrontent sur un graphe orienté biparti $G=(S,A)$ où $S$ est constitué des sommets contrôlés par le joueur 1, $S_1$, et de ceux contrôlés par le joueur 2, $S_2$. Chaque sommet est une position valide du jeu et chaque arête est un mouvement autorisé entre ces positions.

Dans le cas d’un jeu d’accessibilité, on attribue à chaque joueur un sous-ensemble de sommets correspondant à des états gagnants qu’il doit atteindre pour… gagner.

Il peut aussi exister un sous-ensemble de sommets correspondant à des états de partie nulle.

Un jeu d’accessibilité est alors défini
par un quadruplet $(G,S_1,S_2,F)$

où $(G,S_1,S_2)$ est une arène et $F$ est l’ensemble des sommets gagnants pour $J_1$.

Exemples

Autre variante du jeu de Nim :

Eve joue en premier et peut retirer autant d’allumettes qu’elle le souhaite dans un tas
du moment qu’elle en prend au moins une
et qu’elle en laisse au moins une.

C’est ensuite au tour d’Adam de retirer des allumettes avec pour tous les tours qui suivent
une contrainte supplémentaire :

on ne peut pas retirer plus de deux fois le nombre d’allumettes prises par son adversaire
au tour précédent.

Le joueur qui retire la dernière allumette gagne.
Il n’y a pas de match nul.

En commençant avec un tas de 5 allumettes,
on obtient l’arène suivante

où chaque sommet est étiqueté par le couple
(nombre d’allumettes présentes,
nombre d’allumettes prenables).

L’arène s’écrit donc :

$$ \begin{aligned} &(G,\color{blue}\{(5,4,0),(3,2,0),(2,2,0),(1,1,0),(0,0,0)\}\color{black},\\ &\color{magenta}\{(4,2,1),(3,3,1),(2,2,1),(1,1,1),(0,0,1)\}\color{black},\color{orange}(0,0,1)\color{black}) \end{aligned} $$

Remarque

Tout jeu impartial à deux joueurs est une variante du jeu de Nim (théorème de Sprague-Grundy).

Un jeu impartial est un jeu tour par tour dans lequel les coups autorisés, ainsi que les gains obtenus, dépendent uniquement de la position,
et pas du joueur dont c’est le tour.

Un jeu qui n’est pas impartial est appelé jeu partisan (le morpion ou les échecs par exemple).

Le morpion :

On part ici d’une partie avancée.

Eve a les ronds et c’est son tour.

Mise au point d’une stratégie gagnante pour Eve

Il faut pouvoir s’assurer qu’Eve arrive sur $F$.

Comment faire ?

Positions gagnantes et attracteurs

Pour déterminer l’ensemble des positions gagnantes pour Eve sur l’arène, on travaille récursivement depuis les sommets de $F$
en suivant les deux préceptes suivants :

  • un sommet d’Eve est gagnant si un de ses arcs sortants le lie à un sommet gagnant.
    Eve n’a alors plus qu’à emprunter ce chemin.







  • un sommet d’Adam est gagnant (pour Eve)
    si tous ses arcs sortants le lie à un sommet gagnant.
    En effet, Adam ne peut alors pas éviter de mettre Eve dans une position gagnante.







Formalisons en définissant la suite $Attr_i(F)$
qui contient l’ensemble des sommets
gagnants après $i$ étapes :

$$ \begin{array}{lll} Attr_0(F) &= &F \\ Attr_{i+1}(F) &= &Attr_{i}(F) \\ &&\cup \{s \in S_1|Succ(s)\cap Attr_i(F) ≠ \varnothing \} \\ &&\cup \{s\in S_2| Succ(s)\subseteq Attr_i(F)\} \end{array} $$

Étant donné que $Attr_i(F) \subseteq Attr_{i+1}(F) \subseteq S$, pour tout $i≥0$, si on suppose le graphe fini,
la suite est croissante et bornée
et donc stationnaire
(à partir d’un certain $i=i_0$,
$Attr_i(F)$ est constante).

Et si $|G|=n$, $i_0$ vaut au plus $n-1$.

On appelle attracteur de $F$ pour le joueur $J_1$
la limite de $Attr_i(F)$.

On le note $Attr(F)$.

Tout sommet dans l’attracteur
est une position gagnante pour $J_1$.

Le complémentaire d’un attracteur
est appelé piège.

Si le joueur 1 est sur une position n’appartenant pas à son attracteur (et appartenant
donc à son piège), cela signifie que :

  • si c’est son tour, tous les mouvements possibles restent dans le piège,
  • si c’est le tour de l’adversaire, celui-ci a toujours au moins une possibilité de laisser le joueur 1 dans le piège.

Cette position est donc perdante…

Dans le cas de la variante de Nim, l’attracteur se réduit à $Attr(G) = \{(0,0,1) , (1,1,0) , (2,2,0) \}$

Le sommet de départ $(5,4,0)$ n’est pas dedans
$\Rightarrow$ c’est perdu pour Eve 😭.

Sur l’exemple du morpion, l’attracteur contient
13 sommets dont celui de départ 🥳.

Programme permettant de calculer l’attracteur

On peut écrire un programme récursif calculant l’attracteur en temps linéaire en $|S | + |A|$
(le parcours complet d’un graphe est au mieux en $O(|S | + |A|)$ car cela correspond à parcourir
les $|S|$ sommets et les $|A|$ arêtes).

Pour éviter de calculer plusieurs fois le même élément, l’algorithme tient à jour, pour chaque sommet $s$, un compteur n des successeurs non encore inspectés (sous la forme d’un dictionnaire) .

def attracteur(G: dict, F: list) -> list:
    """
    préconditions : G est est un graphe sous forme de liste d'adjacence implémentée par un dictionnaire
                    F est la liste des sommets gagnants pour le joueur 1
    postcondition : la fonction retourne l'attracteur de F pour le joueur 1 sous forme d'un dictionnaire
                    dont les clés sont les sommets de G et les valeurs True ou False suivant que le sommet appartienne ou non à l'attracteur
    """
    Pred = inverseGraphe(G)
    n = {s:len(G[s]) for s in G}
    Attr = {s:False for s in G}
    for sommet in F :
        Joueur1 = True
        propage(sommet,Joueur1,Attr,Pred,n)
    return Attr

def propage(sommet,Joueur1,Attr,Pred,n) :
    if Attr[sommet] :
        return
    Attr[sommet] = True
    for s in Pred[sommet] :
        n[s] -= 1
        if Joueur1 or (n[s] == 0) :
            propage(s,not Joueur1,Attr,Pred,n)

Stratégie sans mémoire gagnante

Une stratégie sans mémoire est une fonction $\sigma$ qui assigne un mouvement autorisé à un joueur pour chaque position non terminale : $\forall s\in S, (s,\sigma(s))\in A.$

Un joueur sur une position $s$ suit une stratégie s’il emprunte le chemin $<s,\sigma(s),\sigma^2(s),\ldots>$.

Elle est dite sans mémoire car pour une position donnée, la stratégie est indépendante du chemin qui y a mené ($\sigma$ ne dépend que du sommet).

Une stratégie sans mémoire gagnante depuis une position donnée garantit la victoire au joueur en un nombre de coups limité.

Pour le joueur 1, une stratégie gagnante garantit d’arriver sur un sommet de $F$.

Mais suivant la position de départ, une telle stratégie n’existe pas forcément…

En construisant l’attracteur,
on répond à notre première question :

La position d’Eve est-elle gagnante ?
$\rightarrow$ Il suffit de vérifier qu’elle
appartient à l’attracteur.

Si c’est le cas, une stratégie gagnante est facile à mettre en place ; il faut faire en sorte que chaque déplacement sur le graphe (chaque coup joué) se fasse vers un sommet de l’attracteur. Chaque coup d’Eve vers un sommet de l’attracteur piège aussi le coup suivant d’Adam dans l’attracteur.

Comme son nom l’indique, l’attracteur attire irrémédiablement vers $F$,
assurant la victoire
au joueur 1.

Le joueur 2 aussi, bien sûr, a son attracteur,
et il appartient au complémentaire de l’attracteur du joueur 1, piège du joueur 1.

Donc un seul écart du joueur 1 en dehors de son attracteur, et s’en est fini pour lui, le joueur 2 peut le condanner à rester dans le piège.

  • Pour Chomp, le joueur 1 appartient à l’attracteur, ce qui signifie que sa position de départ est gagnante. Par conséquent, il a une stratégie gagnante. Mais attention à ne pas se tromper au début ! Sur 5 mouvements possibles, le seul assurant la victoire est de manger le carré en haut à droite.
  • Pour la variante de Nim, c’est foutu ! Quelle que soit notre stratégie, elle sera perdante…

  • Enfin, pour le morpion, la victoire tend les bras au joueur 1. Et, sans surprise, son premier mouvement doit être de prendre
    le milieu.

Algorithme du minimax

Algorithme star pour les jeux. C’est ce type d’algorithme que Deep Blue a utilisé
pour battre Kasaparov en 1997.

Le principe de l’algo est proche de celui de l’attracteur, mais il est plus souple et permet surtout de n’explorer qu’une petite partie de l’arène (au détriment de sa performance).

Le plus grand changement par rapport au raisonnement sur l’attracteur : on transforme
le graphe de l’arêne en arbre.

  • Avantage ?

  • Inconvénient ?

Le but va être de trouver un chemin entre la racine de l’arbre et une feuille gagnante (victoire finale).

L’idée est, comme pour l’attracteur,
de partir de la situation finale et de remonter récursivement tour par tour.

On score chaque feuille terminale
avec une valeur de $+\infty$ si le joueur 1 gagne
et de $-\infty$ si c’est le joueur 2.

On remonte ensuite niveau par niveau :

  • si c’est le tour du joueur 1, on choisi le sommet au plus grand score (max)
  • si c’est au joueur 2, on choisi le sommet au plus petit score (min)

Chaque joueur simulé joue bien ainsi
de manière optimale.

L’intérêt majeur de minimax est la possibilité
de partir de n’importe quel niveau
et pas seulement des positions finales !

On peut donce se contenter de regarder
seulement quelques coups à l’avance.


Quel est l’intérêt ?

Mais pour se limiter à une certaine profondeur dans l’arbre, il faut pouvoir scorer
les sommets du niveau de départ !


On utilise alors une heuristique.

Une heuristique est une méthode de calcul qui fournit rapidement une solution réalisable,
pas nécessairement optimale ou exacte,
pour un problème d’optimisation difficile.
Une heuristique est donc un compromis entre d’un côté l’optimalité (trouver la meilleure solution) et/ou la complétude (trouver toutes les solutions) de l’algorithme et de l’autre côté sa vitesse.

Exemples :

Au morpion, si c’est au tour du joueur 1, on peut compter le nombre de diagonales encore possibles pour le joueur 1 et soustraire le nombre de celles encore possibles pour le joueur 2.

L’arbre total du morpion n’est pas si gros :
le facteur de ramification $b$ est de 5 en moyenne et il y a au plus 9 niveaux (9 coups),
ce qui donne $\approx 5^9 = 1\,953\,125$

Aux échecs, $b\approx35$ et un partie dure en moyenne 100 coups, ce qui donne $b^m\approx10^{54}$
sommets à inspecter…

Minimax inspecte en réalité environ 4 fois moins de sommets que les deux millions prédits (beaucoup de parties se terminent
avant le neuvième coup).

Il en inspecte néanmoins beaucoup trop puisqu’il n’y a que $9!=362\,880$ coups possibles
si l’ordi commence.

Cela illustre le fait qu’un arbre contient beaucoup de sommets redondants par rapport au graphe
du jeu dont il est tiré (c’est le prix à payer
pour casser les cycles).

Problème du sac-à-dos

Le problème du sac-à-dos est
un probème clé d’optimisation.

Il s’agit de choisir des objets ayant une certaine valeur et un certain poids pour les mettre dans
un sac ayant une capacité maximum
(un poids à ne pas dépasser).

On souhaite obtenir le sac de plus grande valeur.

On ne s’occupe ici que de la version la plus simple du problème dite knapsack 0-1 où un objet est soit présent une seule fois dans le sac, soit absent.

Le problème du sac-à-dos est un problème d’optimisation sous contrainte et une foule de défis scientifiques et industriels peuvent se mettre sous cette forme. Son importance est colossale.

Supposons que l’on ait $n$ objets.

Un algorithme force brute consiste
à étudier les … possibilités.

Et dès qu’il s’agit d’explorer un ensemble de combinaisons, la récursivité est l’outil de choix.

Supposons que l’on cherche à placer les objets suivants dans un sac de capacité 900.

objets 🥏 🎺 🥊 🧸 🪠
valeurs $v$ 5 50 65 20 10 12
poids $p$ 320 700 845 180 70 420
def KS(v,p,c,i,valeur,poids):
    n = len(v)
    if i == n: # cas de base (i = n-ième objet)
        if poids > c:
            return 0
        else:
            return valeur
    else:
        valeurAvec = valeur + v[i]
        poidsAvec = poids + p[i]
        return max(KS(v,p,c,i+1,valeur,poids),KS(v,p,c,i+1,valeurAvec,poidsAvec))

C’est bien sûr trop long si le nombre
d’objets devient conséquent.

Pour accélérer les choses, on peut se tourner vers une stratégie gloutonne (stratégie étape par étape où un critère de classement permet de sélectionner le prochain objet à ajouter).

La complexité devient alors …

Le ratio valeur/poids de chaque objet
semble un bon critère.

objets 🥏 🎺 🥊 🧸 🪠
ratio $v/p$ 1/64 1/14 1/13 1/9 1/7 1/35

Problème : ça ne marche pas forcément…

Ici, on se retrouve avec 🪠 et 🧸 dans le sac
pour une valeur de 30€ ce qui n’est
évidemment pas optimal.

Une autre démarche consiste à construire l’abre binaire comme pour l’approche force brute mais en l’élaguant au fur et à mesure quand des branches ne peuvent plus donner la solution.

C’est la méthode “séparation et évaluation”
(branch and bond ou BB en anglais).

Ici, deux élagages possibles :

  • lorsque tout objet ajouté dépasse la capacité, pas la peine d’aller plus loin.
  • et si la valeur maximale du sous-arbre est inférieure à la valeur trouvée par l’approche gloutonne, pas la peine non plus d’aller plus loin.

On se sert donc ici de l’approche gloutonne
comme d’une …

Exemples tirés du TP

Retour site