Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Constant SVG_DPI already defined in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 75
Warning: Undefined variable $ml_array in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 264
Warning: Undefined array key "inResponsiveUnits" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 282
Warning: Undefined array key "hasCssClasses" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 301
Warning: Undefined array key "print" in /home/goupillf/wiki.goupill.fr/lib/plugins/svgembed/syntax.php on line 322
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Warning: Undefined array key 2 in /home/goupillf/wiki.goupill.fr/lib/plugins/codeprettify/syntax/code.php on line 214
Table des matières
Présentation des réseaux de neurones
Les réseaux de neurones artificiels sont une technique d'intelligence artificielle vaguement inspirée par les vrais neurones de notre cerveau. L'idée vient de deux neurologue, Warren McCulloch et Walter Pitts à la fin des années 1950.
Prise de décision
Ce que l'on appelle intelligence artificiel a beaucoup évolué avec l’essor des techniques et pose constamment la question de ce qu'on appelle « intelligence ». Pendant longtemps (et peut-être encore aujourd'hui) l'intelligence artificielle relève d'une prise de décision, d'une reconnaissance automatique.
Prenons un exemple.
On étudie une population d'individus. Ces individus ont tous une paire d'attributs, $x$ et $y$, ce qui permet de placer chaque individu dans un nuage de points. On sait également que certains individus sont du genre rond bleu et d'autres du genre carré rouge.
Pour une variante plus réaliste, prenez le cas des iris (fleurs) que vous avez étudié dans le cadre de l'algorithme KNN (déjà de l'intelligence artificielle). Les iris peuvent être de 3 espèces différentes – Versicolor, Virginica et Setosa – et on souhaite deviner l'espèce d'une iris seulement en connaissant les dimensions (longueur et largeur) d'un pétale.
Il est important de noter que chaque individu a sans doute beaucoup d'attributs. On a choisi seulement les attributs $x$ et $y$ en espérant qu'il suffiront.
Quand on essaie de décider si un individu risque de développer telle maladie, on va noter des informations le concernant : son age, son poids par exemple. Mais un individu ne se résume pas à deux caractéristique. On pourrait noter ce qu'il mange, l'endroit où il vit, sont groupe sanguin… Le travail du statisticien est de réussir à isoler les informations pertinentes, celles qui permettent de décider, les informations discriminantes.
Un des intérêts des méthodes d'intelligence artificielle est qu'on a la possibilité de conserver beaucoup d'attributs, même des attributs a priori non pertinents.
Sur le graphique, j'ai ajouté un losange avec un « ? ». C'est un individu dont on ne connaît pas le genre. Est-il carré rouge ou rond bleu ? Ce cas semble facile, il a plutôt l'air d'être du côté des rond bleus. Bien sûr en situation réelle, c'est plus difficile car les nuages de points ne sont pas aussi nettement séparés et le plus souvent, on doit prendre en compte beaucoup plus que 2 attributs et il est donc impossible de faire un graphique en 2 dimensions.
Quand on fait de la reconnaissance de caractère, on considère une image représentant le caractère que l'on veut reconnaître. L'image peut faire par exemple 15 pixels de haut sur 12 de large. Chaque pixel peut être vu comme un attribut, ce qui nous donne $15\times 12 = 180$ attributs. On ne pourra pas faire un nuage de points en 180 dimensions !
Nous souhaitons donc réaliser un automate qui, quand on lui présente un individu inconnu, décide de la catégorie de cet individu. Ce que l'on connaît de l'individu, ce sont ses attributs $x$ et $y$ que nous transmettons à la machine et la machine prend sa décision seulement sur cette information.
On peut chercher une droite séparant les deux nuages. Cette droit a une certaine équation cartésienne $a\cdot x + b\cdot y + c = 0$ – on préfère cette forme qui est plus générale que $y = m\cdot x + p$ – où $a$, $b$ et $c$ ont une certaine valeur qu'il faudra trouver.
Cette droite coupe le plan en deux parties. Une partie où $a\cdot x + b\cdot y +c > 0$ et l'autre où $a\cdot x + b\cdot y + c < 0$. Avec notre individu inconnu nous calculons $a\cdot x_?+b \cdot y_? + c$ et comme nous constatons que le résultat est $<0$ nous concluons que l'individu est du côté rond bleu.
La quantité $a\cdot x+b \cdot y+c$ est importante et nous allons la noter $h$.
$$h = a\cdot x + b\cdot y + c$$
$h$ peut prendre n'importe quelle valeur mais ici on veut juste savoir si $h > 0$ ou si $h < 0$. On voudrait quelque chose de plus simple. On voudrait un résultat qui vaut 1 ou 0. On voudrait 1 pour les carrés rouges et 0 pour les ronds bleus. Donc on voudrait une fonction $f(h)$ définie par :
$$f(h) = \begin{cases}1 \text{ si } h>0 \\\\ 0 \text{ si }h <0\end{cases}$$
Ce qui donne la machine ci-dessous :
Il ne nous reste qu'à trouver les bonnes valeurs de $a$, $b$ et $c$.
Exercice 1
Dans le fichier iris.csv on vous donne une liste d'individus, des iris, donc on fournit les dimensions des pétales. On pourra prendre $x = $ longueur pétale ; $y =$ largeur pétale. La décision que l'on veut produire est « Est Setosa » qui est vraie pour une iris de l'espèce Setosa et fausse pour les autres.
- Exécutez le programme ci-dessous pour afficher le nuage de points.
- Déterminez une équation $a\cdot x + b\cdot y + c = 0$ qui sépare les points des Setosa des autres.
- Complétez le programme en écrivant une fonction
est_setosa(longueur:float, largeur:float) → boolqui décide si une iris, dont les pétales ont une longueur et une largeur connue, est de l'espèce Setosa. - Exécutez la fonction sur l'ensemble des individus de
datapour vous assurer que le résultat est bien celui attendu.
import csv
import matplotlib.pyplot as plt
# extraction des données du fichier
def formatage(row):
return {
'petal_length':float(row['petal_length']),
'petal_width':float(row['petal_width']),
'species':row['species']
}
with open('iris.csv', encoding='utf8') as file:
reader = csv.DictReader(file, delimiter=',')
data = [formatage(row) for row in reader]
def plot_sub_cloud(species, color):
"""
Trace le nuage des point d'une certaine espèce
color indique la couleur désirée
"""
x = [item["petal_length"] for item in data if item["species"] == species]
y = [item["petal_width"] for item in data if item["species"] == species]
if len(x) > 0:
plt.scatter(x, y, c=color, label=species)
plot_sub_cloud('setosa', 'b')
plot_sub_cloud('versicolor', 'g')
plot_sub_cloud('virginica', 'r')
plt.legend()
plt.show()
Apprentissage
Logique floue
Ce qui précède nous donne l'idée générale mais il reste un ingrédient très important : Nous souhaitons que notre machine détermine automatiquement les valeurs de $a$, $b$ et $c$.
Nous souhaitons fournir à notre machine les individus déjà connus et déjà classés qui lui permettront d'apprendre toute seule comment elle doit se régler pour continuer à trier des individus inconnus.
Imaginez un enfant auquel on répète « ça c'est un chat », « ça c'est un oiseau » et qui apprend tout seul comment reconnaître un oiseau d'un chat, sans qu'on ait eu besoin de lui expliquer qu'un chat a 4 pattes et qu'un oiseau a un bec. Il suffit qu'on lui montre des exemples pour qu'il devine seul ce qui fait la différence entre les deux et qu'il sache à l'avenir faire le tri entre des chats et des oiseaux, même s'il découvre des oiseaux exotiques qu'il n'avait jamais vu avant.
Cette forme d'apprentissage est appelée apprentissage supervisé car on supervise l'apprentissage en présentant des exemples déjà triés.
Dans le cadre de l'apprentissage, notre fonction $f$ va poser problème.
Nous avons dit qu'il s'agissait de trouver une droite séparant les deux nuages. Mais plusieurs droites sont possibles. Ci-dessus, la verte et la rose conviennent. Pourtant on sent que la verte est meilleure. Elle coupe plus au centre de la zone séparant les nuages.
Notre fonction $f$ ne permet pas de faire la différence. Avec cette fonction, on ne considère qu'une seule chose, qu'un point soit d'un côté ou de l'autre de la droite. Qu'il en soit loin ou proche ne change rien. Une logique plus floue serait sans doute préférable. Ainsi on préférerait que la machine produise un résultat entre 0 et 1 :
- plutôt 0 pour un point bleu
- plutôt 1 pour un carré rouge
- 0,5 sur la droite
- une variation continue : par exemple 0,6 proche de la droite du côté point rouge…
Sur cette figure on voit une notion de flou autour de la droite. Cette façon de faire est plus réaliste et va permettre de donner une importante au fait qu'un point est éloigné ou proche de la droite.
La logique floue est d'ailleurs un domaine de l'intelligence artificielle !
La fonction $f$ est maintenant une fonction passant progressivement de 0 à 1. Cette fonction qui évoque vaguement un S est appelée sigmoïde et a pour formule :
$$f(h) = \frac{1}{1+\exp(-h)}$$
Remarque compliquée pouvant être ignorée : deux équations de droites peuvent être équivalents, par exemple $3x + 2y + 1 = 0$ et $6x + 4y + 2 = 0$. C'est ennuyeux car nous cela revient à dire qu'on ne devrait pas avoir 3 paramètres à régler mais seulement 2. Avec la sigmoïde, le 3e paramètre reprend de l'intérêt car il permet de régler la raideur de la sigmoïde, c'est à dire l'intensité du flou.
Algorithme
Voici maintenant le principe de l'apprentissage :
- on choisit au hasard les valeurs de $a$, $b$ et $c$,
- pour chaque individu $(x\,;\;y)$ on calcule la valeur de $s = f(a\cdot x + b\cdot y + c)$ et on compare avec la valeur attendue $s_{attendu}$ pour cet individu
- on fait une mesure d'erreur totale, c'est à dire que l'on évalue un total des écart entre les $s$ et les $s_{attendu}$ attendus,
- on rectifie les valeurs de $a$, $b$ et $c$ pour réduire l'erreur totale.
- on recommence en 2 suffisamment de fois pour réduire l'erreur aussi bas que l'on peut
Petit à petit, le réglage va s'ajuster et les coefficients vont atteindre une bonne valeur.
Le résultat n'est pas garanti ! Si on a mal choisi la base d'apprentissage, si les attributs sont mal choisis, si les nuages de points ne sont pas assez bien séparés… Certains disent que ce qu'il y a d'intelligence dans l'intelligence artificielle est l'intelligence que les chercheurs ont mis à choisir les bons paramètres, les bonnes données… pour que la machine finale fonctionne.
Distance
La méthode proposée est encore vague : nous devons définir comment on compare $s$ et $s_{attendu}$ et comment cette comparaison modifie les paramètres $a$, $b$ et $c$.
On commence par choisir une formule pour évaluer l'erreur entre $s$ et $s_{attendu}$. On notera $\mathcal{E}$ l'erreur.
$$\mathcal{E} = \frac{1}{2}\sum_{individus} (s-s_{attendu})^2$$
Le $\frac{1}{2}$ n'est pas indispensable et sert seulement à simplifier les formules à suivre. $s - s_{attendu}$ semble aller de soi. Le carré permet d'avoir une un écart toujours positif, mais on aurait pu prendre $\sqrt{(s-s_{attendu})^2}$ c'est à dire $|s-s_{attendu}|$, mais $(s-s_{attendu})^2$ s'avère un bien meilleur choix notamment car cela rend les calculs beaucoup plus simples. On somme ($\sum$) sur tous les individus.
Gradient
On voudrait modifier $a$, $b$ et $c$ pour réduire l'erreur. On se demande donc : si je modifie un peu $a$, d'une quantité $da$ (ici le $\delta$ signifie une variation infinitésimale, un petit écart, un petit delta, c'est le langage de la dérivation) de combien cela va modifier $\mathcal{E}$ ? C'est typiquement un calcul de dérivation.
En notation physique on aura
$$\frac{d\mathcal{E}}{da} = \sum_{individus}(s-s_{attendu})\cdot f'(h) \cdot x \quad \text{avec }h = a\cdot x + b\cdot y + c$$
- Si $\frac{d\mathcal{E}}{da} > 0$ cela veut dire que l'erreur augmenterait si on augmentait $a$. Il faudrait alors diminuer $a$.
- Si $\frac{d\mathcal{E}}{da} < 0$ cela veut dire que l'erreur diminuerait si on augmentait $a$. Il faudrait alors augmenter $a$.
On choisit de faire varier $a$ de la quantité
$$da = -\lambda \cdot \frac{d\mathcal{E}}{da} = -\lambda \cdot \sum_{individus}(s-s_{attendu})\cdot f'(h) \cdot x$$
où $\lambda$ est un paramètre qu'il faut ajuster en bricolant un peu – part de savoir faire… – et on peut choisir $\lambda = 0,1$ – l'expérience montre que ça fonctionne bien avec $\lambda = 0,1$.
Nous avons précisé les étapes 4 et 5 :
- $a$ change de la quantité $da = -\lambda\cdot \sum_{individus} (s-s_{attendu})\cdot f'(h) \cdot x$
- $b$ change de la quantité $db = -\lambda\cdot \sum_{individus} (s-s_{attendu})\cdot f'(h) \cdot y$
- $c$ change de la quantité $dc = -\lambda\cdot \sum_{individus}(s-s_{attendu})\cdot f'(h)$
Exercice 2
Vous pouvez reprendre le chargement de données du fichier précédent. Il va falloir le modifier un peu.
- Modifiez le formatage de sorte que pour chaque fleur de
iris.csvon obtienne un tuple(x, y, sa)oùxreprésente la longueur du pétaleyreprésente la largeur du pétalesareprésente le résultat attendu. 1 pour une Setosa et 0 sinon.
- Écrivez une fonction
calc_h(x, y, a, b, c)qui calcule $h = a\cdot x + b\cdot y + c$ - Écrivez une fonction
f(h)qui calcule $f(h)$ - Écrivez une fonction
fp(h)qui calcule $f'(h)$ (je vous laisse déterminer l'expression de $f'$) - Écrivez une fonction
g(data, a, b, c)
datareprésente l'ensemble des données sous la forme[(x0, y0, sa0), (x1, y1, sa1), ...]
Cette fonction fait le calcul les trois valeurs et les renvoie :- $g_a = \sum_{individus} (s-s_{attendu})\cdot f'(h) \cdot x$
- $g_b = \sum_{individus} (s-s_{attendu})\cdot f'(h) \cdot y$
- $g_c = \sum_{individus} (s-s_{attendu})\cdot f'(h)$
- Écrivez une une fonction
apprentissage(data)qui initialise $(a,b,c)$ aléatoirement puis réalise une centaine de fois le calcul :
$$(a,b,c) \leftarrow (a -\lambda\cdot g_a, b - \lambda \cdot g_b, c - \lambda\cdot g_c)$$
On pourra utiliser une constante LAMBDA = 0.1
Exécutez le calcul et vérifiez que le triplet $(a, b, c)$ obtenu est valide.
Base d'apprentissage, base de test
On peut dire aussi entraînement pour apprentissage.
Comme vous l'avez vu, il nous faut un fichier de données pour entraîner notre neurone.
On souhaite bien-sûr que notre neurone, une fois entraîné, ne fasse pas (ou très peu) d'erreurs sur les items de cette base.
Mais ça ne suffit pas : nous voulons que le neurone réponde juste pour des items qui n'étaient pas dans la base (sinon quel intérêt ?)
Pour vérifier que c'est bien le cas, on constitue une base de tests contenant d'autres individus, absents de la base d'apprentissage. On connaît $s_{attendu}$ pour ces individus et ainsi on peut vérifier que le neurone fait bien ce qu'il devrait.
Réseau
La machine étudiée est très limitée. On voit qu'elle en peut rien faire dans un cas plus complexe.
D'ailleurs, il n'y a pas de réseau dans notre machine : elle ne contenait qu'un neurone !
On va relier des neurones entre eux, constituant ainsi un véritable réseau.
Ci-dessous, chaque ellipse représente une machine équivalente à celle étudiée précédemment.
Les mathématiques nécessaires ne vont pas être beaucoup plus complexe. Il faudra, en fonction des erreurs constatées en sortie, modifier les réglages de chaque neurone en remontant de la sortie vers les entrées. On appelle cela la rétro-propagation du gradient.
En revanche, le bon fonctionnement de l'apprentissage va beaucoup dépendre de la façon dont on branche les neurones entre eux. Bien choisir les branchements et les paramètres de réglage devient une cuisine délicate.
Pendant longtemps, les réseaux de neurones ont été peu utilisés par ce que l'on pensait qu'ils n'étaient pas tellement efficaces. Certains chercheurs, comme Yann le Cun, ont continué à travailler sur le sujet et ont découvert que l'on pouvait obtenir de bons résultats avec des réseaux de neurones plus compliqués. On a a lors parlé d'apprentissage profond et les réseaux de neurones sont devenus à la mode dans la recherche.
Effet boîte noire
Les réseaux de neurones ont un gros défaut que l'on peut expliciter sur l'exemple de AlphaZero, le système de Google, champion d'échecs.
Lorsque l'on développe un logiciel de jeu d'échecs et que l'on veut que l'ordinateur joue, il faut fournir à l'ordinateur des fonctions qui lui permettent d'évaluer une situation de jeu. Alors on doit réfléchir à ce qui fait qu'une position vaut mieux qu'une autre et on doit développer toute une théorie du jeu d'échecs. À la fin, on a de solides connaissances sur le jeu.
Avec AlphaZero, on dote la machine de la capacité de tenter des coups. Elle tente donc au hasard (parmi les coups autorisés bien sûr). Le seul critère d'évaluation vient de la victoire ou défaite finale. Puis on laisse l'ordinateur jouer des millions de parties. À la fin, il sait jouer et joue même très bien. Mais on n'a aucun moyen de savoir quels sont les critères qu'il utilise pour un coup. On peut lire son paramétrage, on peut obtenir tous les coefficients de son réseau de neurones, mais de savoir que tel coefficient vaut par exemple 0.42366657 ne nous avance pas à grand chose.
Le réseau de neurone a un côté boîte noire. Il fonctionne mais on ne sait pas comment. Cela peut-être gênant dans des cas où la sécurité est importante : On aura beaucoup de mal à garantir que la machine fonctionne à tous les coups. On l 'a bien entraînée, elle semble très bien fonctionner, mais peut-on garantir qu'il n'y aura pas un cas particulier où elle fait n'importe quoi ?
Module sklearn
Le module sklearn de python contient quantité d'éléments utiles pour l'intelligence artificielle.
On pourra notamment y trouver le Perceptron qui est une façon d'organiser un réseau de neurones.
Supposons que mes données se séparent entre X la liste des entrées de mon réseau et Y, les sorties attendues, il suffira de :
from sklearn.linear_model import Perceptron rn = Perceptron(tol=1e-3) rn.fit(X,Y)
Ici rn est l'objet contenant notre réseau de neurones.
Voici un exemple que vous pouvez tester.
import csv
from sklearn.linear_model import Perceptron
with open('iris.csv', encoding='utf8') as file:
reader = csv.DictReader(file, delimiter=',')
X = [] # paires (petal_length, petal_width)
Y = [] # étiquettes : 1 pour setosa, 0 sinon
for row in reader:
l = float(row ["petal_length"])
w = float(row ["petal_width"])
X.append((l,w))
if row['species'] == 'setosa':
Y.append(1)
else:
Y.append(0)
# création du réseau
rn = Perceptron(tol=1e-3)
# apprentissage
rn.fit(X, Y)
# on peut voir ce que prédit notre réseau pour les fleurs du fichier
# on obtient une liste de 0 et de 1 correspondant aux espèces
# vous pouvez voir qu'il ne se trompe pas !
print(rn.predict(X))
Si on veut étendre la prédiction aux virginica et versicolor, le résultat n'est pas bon. Pour mieux faire, on ajoute la prise en compte des sépales. De plus, on n'est pas obligés d'imposer 1 et 0 en sortie. On peut directement indiquer les étiquettes désirées.
import csv
from sklearn.linear_model import Perceptron
with open('iris.csv', encoding='utf8') as file:
reader = csv.DictReader(file, delimiter=',')
X = [] # paires (petal_length, petal_width)
Y = [] # étiquettes : 1 pour setosa, 0 sinon
for row in reader:
pl = float(row ["petal_length"])
pw = float(row ["petal_width"])
sl = float(row["sepal_length"])
sw = float(row["sepal_width"])
X.append((pl, pw, sl, sw))
Y.append(row['species'])
# création du réseau
rn = Perceptron(tol=1e-3)
# apprentissage
rn.fit(X, Y)
# on peut voir ce que prédit notre réseau pour les fleurs du fichier
# on obtient une liste de 0 et de 1 correspondant aux espèces
# vous pouvez voir qu'il ne se trompe pas !
print(rn.predict(X))
# et on peut faire un compte des succès :
Yp = rn.predict(X)
count = 0
for i in range(len(Y)):
if Y[i] == Yp[i]:
count += 1
print(count/len(Y))
On obtient environ 95 % de succès !
Le travail de formatage est un peu fastidieux. On gagne beaucoup de temps en utilisant Pandas.
import pandas
from sklearn.linear_model import Perceptron
train = pandas.read_csv("iris.csv")
rn = Perceptron(tol=1e-3)
X = train[['sepal_length', 'sepal_width', 'petal_length', 'petal_width']]
Y = train['species']
rn.fit(X, Y)
print(rn.predict(X))
Dans cet exemple, j'utilise predict sur les individus de la base d'apprentissage. C'est un peu absurde : le perceptron a appris avec ces données, ce n'est pas une prédiction mais une récitation de ce qu'il a appris ! Pour mieux faire, il faudrait proposer constituer un fichier de test avec des iris absentes de la base d'apprentissage.
Exemples d'applications
Vous pouvez essayer d'appliquer cette méthode dans le problème du Titanic.
