Méthode constructive de recherche fondamentale mathématique-informatique en s'inspirant des réseaux de neurones.

Table des matières

  1. Introduction
  2. La variable

2) Construction inspirée des réseaux de neurones

Nous allons nous inspirer des algorithmes biomimétiques mais sous un angle différent que ceux communément décrit par les économistes et les psychologues, en les généralisant à l'aide de notre approche mathématique constructive. Le mimétisme biologique ne doit pas nous mettre des oeillères, et si la nature est source de la plus part des découvertes tel que en chimie par exemple, nous ne sommes pas contraint comme elle de ne partir de rien. Notre ambition est de produire une intelligence sur-naturelle.

La question qui se pose est, est-il possible de développer des recherches fondamentale en mathématique-informatique, en s'inspirant des réseaux de neurones, de façon constructive, c'est à dire totalement ouverte, en choisissant la solution constructive la plus générale possible, et en assurant la plus grande interopérabilité possible dans toutes les constructions qui seront faite. C'est ce que nous nous proposons de faire sous forme d'un jeu et d'une discution philosophique

1) Introduction

Nous allons nous inspirer des algorithmes biomimétiques mais sous un angle différent que ceux communément décrit par les économistes et les psychologues, en les généralisant pour étudier les fondement des mathématiques et de l'informatique. Le mimétisme biologique ne doit pas nous mettre des oeillères. La nature est source de la plus part des découvertes tel que en chimie par exemple, nous en sommes convaicu, mais nous ne sommes pas contraint comme elle de ne partir de rien. Notre ambition reste de produire une intelligence sur-naturelle.

Le neurone que nous utilisons est plus général, il s'agit en fait d'une variable dans un système d'équation différentiel.

Le langage mathématique a mis en évidence un objet singulier qu'est la variable, porteuse d'une donnée ou d'un calcule intermédière. Et il a mis également en évidence un second objet qu'est la fonction (ou l'opérateur). Mais déja certain vous dirons qu'il s'agit du même objet. Pour les distinguer il faut approfondire, les caractériser dans leurs fonctionnements propres, les refroidirent comme par analogie aux particules physiques qui ne se différencient et se caractèrisent que lorsque leurs niveaux d'énergies descendent en dessous d'un certain seuil.

Par exemple, la fonction calculable, car en mathématique constructive seul celle-la nous intéresse, est un algorithme défini à partir d'autres plus petites fonctions, de tel sorte que la fonction calculable n'est pas restreinte à son seul sense commun et à son domaine de définition tel qu'il est classiquement décrit, mais peut être appliqué à d'autre domaine ou au même domaine, avec un sense différent, en traduisant les petites fonctions dont elle est composé, par d'autres applicables au domaine choisi, mais qui doivent néamoins respecter certaines règles, appellées axiomes, garrantissant leur comportement prévue au sein de la fonction mère.

Les mathématiques ont choisie de regrouper les définitions des fonctions élémentaires (les plus petite fonction qui composent toutes les autres fonctions) dans les sructures des données, de tel sorte qu'une fonction appliqué à un élément aura un comportement dépendant de la structure à qui appartient l'élément. Et la fonction ne pourra être appliqué à l'élément que si la structure de l'élément possède ces fonctions élémentaires avec leurs propriétés axiomatiques voulu. Ce choix inspiré de la programmation objet ne semble pas restrictif.

Pour l'instant nous ne précisons pas le type de donnée utilisé, par défaut pensez qu'il s'agira des "float double" tel qu'ils sont définie informatiquement, car il faut bien penser à quelque chose pour ordonner l'intuition.

Le neurone que nous choisissons est une variable. Le plus souvent cette variable sera définie égale à une fonction calculable f(x1, x2, x3..., xn) possédant n variables x1, x2, x3..., xn. L'analogie avec le neurone devient alors évidente, les différentes places pour les variables de la fonction jouent le rôle des synapses, mais ici chaque synapse a un rôle différent car la fonction n'est pas apriori symétrique, et le résultat de la fonction qui est identifié à une variable, est l'axone du neurone. Chaque entrée est une variable, c'est à dire est reliée à un autre neurones. Le neurone est identifié à sa variable de sortie qui transmet la valeur de la fonction, et cette sortie peut être raccordée à autant de neurone que l'on veut.

A ce stade il manque deux éléments essentiels que sont la mémoire et la source des données. C'est pourquoi sans altérer la généralité, on peut définir deux autres types de neurones, qui eux ne possèdent pas de synapse, qui sont les neurones "mémoire" qui contiennent une valeur en mémoire et les neurones "input" qui raccordent le réseau à une source de données.

Une fois posé ces quelques définitions essentielles, nous pouvons construire les algorithmes qui permettent de calculer la valeur du réseau ainsi que les dérivés partielles premières et secondes du réseau.

Selon la programmation orienté objet, nous précisons les méthodes de chaque classe, ainsi que la hierachie des classes. La classe la plus générale étant la classe Variable. Les classes Neurones, Neurone-Input et Neurone-Mémoire héritent de la classe Variable. Ainsi les champs et méthodes de la classe Variables ne sont pas répétés .

Variable :
  N : Nom de la variable.
  R : Nom du reseau.
  P : Liste des noms des neurones pères.
  x : Valeur de la variable.
  t : Date de la valeur x.

Neurone : Variable
  f : Fonction du neurone.
  n : Nombre de variables du neurone.
  F : Liste des noms des neurones fils dans l'ordre des entrées dans la fonction f.
  B : Liste des entrées de la fonction f qui ne sont pas liées à une variable.
  Eval() : Valeur du neurone.
  Valeur (i) : Valeur de la i ième entrée du neurone.
  Nom(i) : Nom de la i ième variable.
  Diff(i) : Différentielle partielle par rapport à la i ième variable du neurone.
  DiffNom(j): Différentielle partielle par rapport à la variable de nom j.
  Local(j) : Numéro de place de la variable de nom j dans le neurone, 0 si c'est le neurone, et -1 si non présent.
  In(j) : Vrai si la variable de nom j est un n ième petit fils du neurone, ou le neurone lui-même.

Neurone-Input : Variable
  Nom : Nom du fichier texte qui contient les données.
  c : Numéro de colonne à partir de 1.
  Lire() : Lit la donnée suivante.

Neurone-Mémoire : Variable

Le choix de la généralité fait qu'une grande partie de la problèmatique qui s'applique au neurone, s'applique également au réseau. De tel sorte que le réseau peut être vue comme un neurone :

Reseau : Neurone
P (j) : retourne la liste des noms de neurones du reseau qui possède la variable de nom j.

Selon le principe d'interopérabilité, il nous faut un langage pour définire un réseau de neurone, permettant ainsi de le copier, et de le transmettre... On suppose des fonctions modèles f, g, h. Les neurones input sont défini avec le mot clés "input", et les neurones mémoire avec le mot clés "mem". Voici un exemple de réseau comprenant cinq neurones normals x1, x2, x3, x4, x5, trois neurones inputs : x6, x7, x8 relié aux données comptenue dans un fichier text "c:\data.txt" dans les colonnes 1, 2 et 3 (le séparateur de colonne est habituellement le caractère ';'), et trois neurones mémoires : x9, x10, x11 dont les valeurs initiales sont 0.4, 0.3 et 0.7 :

x1 = f(x2,x3,x4,x5)
x2 = h(x9,x6,x5)
x3 = g(x10,x7,x5,x6,x4)
x4 = f(x4,x9,x10)
x5 = h(x8,x11,x9)
x6 = input("c:\data.txt",1)
x7 = input("c:\data.txt",2)
x8 = input("c:\data.txt",3)
x9 = mem(0.4)
x10 = mem(0.3)
x11 = mem(0.7)

Le choix du type de donné, de sa structure, (reel avec quel précision, quaternionique, entière, vectoriel, ensemble, serie, n-uplet à permutation circulaire près, ou toute autre structure...) est une question qui repose le tout. Cette question intègre les règles de symétrie des fonctions. A savoir, si f(x,y) est une fonction symétrique, c'est à dire si x et y sont de même type et si f(x,y) = f(y,x), alors f(x,y) peut être remplacé par f(z) où le type de z est le type des couples à permutation près d'élément de même type que x.

La recherche de la généralité fait que nous n'allons pas tout de suite rentrer dans la complexité de ce choix. Nous avençons prudemment en apportant le stricte nécessaire à chaque étape du développement afin de minimiser le risque de prise de choix restreignant la généralité.

L'algorithme de calcule du neurone est le suivant :

Eval() :
f(Valeur(i) $ i = 1..n)

application la fonction f à cette liste.

....

Comme il y a homotécie et qu'un réseau est un neurone, on peut tout de suite se plonger à l'echelle la plus petite, là où les fonctions sont élémentaires. Si nous considérons des structures simples, les fonctions élémentaires sont en nombre réduit. Si nous considérons da structure des entiers de péano, il n'y a qu'une fonction de base

 

La variable aléatoire se comporte comme une fonction dont le domaine de définition correspond aux index de tirages. Cela peut être les entiers naturels désignant une infinité dénombrable de tirages en commençant par l'index 0. Ou cela peut être un domaine continue [0,1] par exemple, désignant une infinité non dénombrable de tirages. L'index est désigné par un reel comme le temps, et la variable représente un signal. Le domaine de définition peut être engendré à partir d'un domaine finie telque les entiers 0,1,2,3..., N-1, en l'étendant aux infinies de la façon suivante : Variables cyclique d'ordre N, et signaux n'admettant pas de fréquence supérieur à 1/2 tours par unité de temps, car d'après le théorème de l'échantillonnage de C.E.Shannon, la description d'un tel signal est exactement décrite par la succetion des valeurs du signal espacées par des pas de 1 unité de temps.

Pour trouver les propriétés les plus remarquables, il est probable que nous choisirons, comme domaine de définition et comme ensemble d'arrivé, d'une structure trés riche tel que les nombres complexes. Il y a des zones attractives ou point froid, en mathématique, et les complexe en font partis comme étant la plus grande structure possible de corps commutatif contenant les réels et constituant un corp algébriquement clos (tout polynome a une racine).

Nous allons commençer à étudier les variables aléatoires ayant comme domaine de définition les entiers naturels, et les reels comme ensemble d'arrivé.

Nous allons définire un certain nombre d'opérateur qui effecturons des calculs et dont nous exhiberons des règles de simplification, pour pouvoir ainsi faire les calculs de simplification à un niveau supèrieur. L'opérateur est un élément abstrait programmable qui nous permet d'avoir une approche purement constructive. Et c'est en se sense que nous les utilisons.

La valeur de la variable aléatoire X pour chaque tirage est notée X(0), X(1), X(2).... X est un vecteur ayant une infinité de composante. X est donc un tenseur d'ordre 1, c'est à dire qu'il peut être décliné selon un indice i, ici entier. On note cette opérateur O(i). L'opérateur O(i) transforme un tenseur d'ordre 1 en une constante qui est un tenseur d'ordre 0.

O(i)(X) = X[i].

O(i) :  T1 --> T0
        X --> X[i]

X étant une fonction, on peut la composer avec d'autre. Par exemple considérons les fonctions f =(a-->2*a), et g=(a-->a^2), nous pouvons construire la variable aléatoire g°X°f.

(g°X°f)(i) = g(X(f(i)))

On voit apparaître le choix d'une notation fonctionnelle qui doit permettre de combiner le plus librement possible des fonctions qui peuvent avoir plusieurs arguments.



 

 

 

 

 

L'obsoléscence des donnés est controlé par leurs dates exprimée par un nombre entier d'unité. Chaque donnée est donc accompagné d'un entier désignant sa date de fraîcheur.

On introduit un neurone de delay G(x,t) qui retourne la valeur x à l'instant - t. Pour les valeurs non entière de t, G(x,t) retourne une extrapolation du deuxième degrés. Pour les valeurs négatives, il y a un processus de récurence avec une condition d'arret consistant à un epsilon de modification et un nombre maximum d'itération posés globalement.

 

 

 

 

L'appentissage, ou la recherche de paramètres pour minimiser une erreur.

Soit une fonction vectorielle f = T(f[1],f[2],f[3]...,f[s]) de s composantes, dépendant d'une donné vectorielle a = T(a[1],a[2],a[3]...,a[m])de m composantes, et d'un paramètre vectoriel x = T(x[1],x[2],x[3]...,x[n]) de n composantes. Et soit une donnée vectorielle b = T(b[1],b[2],b[3]...,b[s]) de s composantes. On recherche un paramètres vectoriel x par tatonnement succéssif telque f = b, méthode de newton, puis après telque T(f-b)*(f-b) soit minimum, méthode des moindres carré.

s représente le nombre d'équations, m représente le nombre de données (n'intervient pas pour l'instant), et n le nombre de paramètres.

T désigne l'opérateur de transposition permettant entre autre de représenter des vecteurs colonnes sous forme de vecteur ligne. On affichera systématiquement les deux notations vectoriel et tensoriel.

1) Méthode de Newton. On a

f = b + e

e = T(e[1],e[2],e[3]...,e[s]) représentant l'erreur qui doit être annulée.

La modification dx = T(dx[1],dx[2],dx[3]...,dx[n]) des paramètres x va entrainer une modification df = T(df[1],df[2],df[3]...,df[s]) de f.

       df[1]/dx[1] df[1]/dx[2] df[1]/dx[3] ... df[1]/dx[n]
       df[2]/dx[1] df[2]/dx[2] df[2]/dx[3] ... df[2]/dx[n]
f' =   df[3]/dx[1] df[3]/dx[2]
df[3]/dx[3] ... df[3]/dx[n]
       ..................................  ...  .........
       df[s]/dx[1] df[s]/dx[2] df[s]/dx[3] ... df[s]/dx[n]

f'[i,j] = df[i]/dx[j]  i=1..s j=1..n

Par soucie de lisibilité on utilisera i pour les seuls indices variant de 1..s (nombre d'équations)
Et on utilisera j,
k et l pour les seuls indices variant de 1..n (nombre de paramètres).

df = f'*dx

df[i] = Sum j=1..n (f'[i,j]*dx[j])  i=1..s

df[i] = Sum j=1..n ((df[i]/dx[j])*dx[j])  i=1..s

Il faut que df soit égale à -e, c'est à dire égale (b-f), afin d'annuler l'erreur.

df = f'dx = b-f

df[i] = Sum j=1..n (f'[i,j]*dx[j]) = b[i]-f[i]  i=1..s

df[i] = Sum j=1..n ((df[i]/dx[j])*dx[j]) = b[i]-f[i]  i=1..s

On rend la matrice f' carré en la multipliant par sa transposé.

T(f')[j,i] = f'[i,j] = df[i]/dx[j]  i=1..s j=1..n

T(f')*f'*dx = T(f')*(b-f)

Sum k=1..n j=1..n (T(f')[j,i]*f'[i,k]*dx[k]) = Sum i=1..s (T(f')[l,i]*(b[i]-f[i]))  l=1..n

Sum k=1..n j=1..n (f'[i,j]*f'[i,k]*dx[k]) = Sum i=1..s (f'[i,l]*(b[i]-f[i]))  l=1..n

Sum k=1..n j=1..n ((df[i]/dx[j])*(df[i]/dx[k])*dx[k])
= Sum j=1..n ((df[i]/dx[l])*(b[j]-f[j]))  i=1..s

On calcul l'inverse de la matrice T(f')*f' que l'on note Inv(T(f')*f') et on obtient la valeur de dx comme suit:

dx = Inv(T(f')*f') * T(f') * (b-f)

 

2) Methode des moindres carrés. On a

f - b = e où e = T(e[1],e[2],e[3]...,e[s]) représente l'erreur.

Posons g = T(f-b)*(f-b) = T(e)*e qui représente la somme des carrés des erreurs que l'on veut minimaliser.

g = Sum i=1..s ((f[i]-b[i])^2)

g = Sum i=1..s (f[i]^2 - 2*f[i]*b[i] + b[i]^2)

g = T(f)*f - T(f)*b - T(b)*f + T(b)*b

g = T(f)*f - 2*T(b)*f + T(b)*b

La modification dx = T(dx[1],dx[2],dx[3]...,dx[n]) des paramètres x va entrainer une modification dg de g.

g' = dg/dx[j]  j=1..n

g' = Sum i=1..s 2(f[i]*(df[i]/dx[j]) - (df[i]/dx[j])*b[i])  j=1..n

g' = Sum i=1..s 2((df[i]/dx[j])*(f[i] - b[i]))  j=1..n

Posons h1 = g'[1] . On cherche à annuler h par la methode de newton

La modification dx = T(dx[1],dx[2],dx[3]...,dx[n]) des paramètres x va entrainer une modification dh1 de h1.

h1 = Sum i=1..s 2((df[i]/dx[1])*(f[i] - b[i]))

h1' = dh/dx[k]  k=1..n

h1' = Sum i=1..s 2((ddf[i]/dx[1]*dx[k])*(f[i]-b[i])+(df[i]/dx[1])*(df[i]/dx[k])) k=1..n

h1' = Sum i=1..s 2((df[i]/dx[k])*(df[i]/dx[1])+ (ddf[i]/dx[1]*dx[k])*(f[i]-b[i]))  k=1..n

dh1 = h1'*dx = -h1
dh2 = h2'*dx = -h2
dh3 = h3'*dx = -h3

.....


g' = 2*T(f)*f' - 2*T(b)*f'

g' = 2*T(f-b)*f'

g'[j] = Sum i=1..s (2*(f[i]-b[i])*f'[i,j])  j=1..n

g'[j] = Sum i=1..s (2*(f[i]-b[i])*(df[i]/dx[j]))  j=1..n

Le vecteur g' est un vecteur ligne : g' = (g'[1],g'[2],g'[3]...,g'[n]).

dg = g'*dx

Nous recherchons un minimum donc nous cherchons à annuler le vecteur g'.

g''*dx = -g'

g'' = 2*T(f')*f'+T(f-b)*f''

 

 

Posons h = g'[1] que l'on veut annuler.

h = Sum i=1..s (2*(f[i]-b[i])*(df[i]/dx[1]))

h'=

La modification dx = T(dx[1],dx[2],dx[3]...,dx[n]) des paramètres x va entrainer une modification dh.

dg = Sum j=1..n (g'[j]*dx[j])

dg = Sum j=1..n i=1..s (2*(f[i]-b[i])*f'[i,j])*dx[j])

dg = Sum j=1..n i=1..s (2*(f[i]-b[i])*(df[i]/dx[j]))*dx[j])
T