Developpez.com - Rubrique HPC

Le Club des Développeurs et IT Pro

Gen, un langage probabiliste universel dans Julia

Il ambitionne de faciliter l'utilisation d'intelligence artificielle pour tous

Le 2019-07-01 19:12:59, par dourouc05, Responsable Qt & Livres
La programmation probabiliste est un paradigme de programmation assez peu répandu, notamment parce que ses utilisations sont liées à l’intelligence artificielle (et pas à grand-chose d’autre). L’objectif est d’effectuer des calculs sur des variables aléatoires (c’est-à-dire une quantité qui n’est pas connue exactement), puis d’effectuer de l’inférence pour expliquer des données. Par exemple, pour de la reconstruction de pose 3D (trouver l’orientation des bras, des torses, des jambes, etc. à partir d’une photo d’une personne), on dispose d’une image à expliquer. Une manière classique d’aborder le problème serait de trouver les bras, le torse, les jambes, puis leurs orientations. En programmation probabiliste, on préférera utiliser une série de variables aléatoires (orientation des bras, des jambes, etc.) : une fois les valeurs fixées, on peut calculer exactement la pose de la personne. Ensuite, on peut comparer l’image obtenue avec celle d’entrée : si elles sont très proches, on a trouvé les bonnes valeurs des variables aléatoires. Le processus d’inférence consiste, ici, à tirer un grand nombre de valeurs différentes pour les variables aléatoires, puis de prendre la meilleure correspondance avec l’image d’entrée, la “meilleure explication”.

Gen est un système prévu pour la programmation probabiliste “généraliste”, sans a priori sur les variables aléatoires que l’on peut utiliser. Ce système est embarqué comme une bibliothèque pour le langage Julia.

En pratique, pour effectuer de l’inférence, il faut deux choses : d’un côté, une fonction génératrice, qui tire au hasard (ou choisit de manière plus intelligente) des valeurs pour les variables aléatoires et détermine d’autres valeurs (une sorte de résultat final : par exemple, une pose) ; de l’autre, des données à expliquer.

Par exemple, on dispose d’une série de coordonnées de points et on cherche une droite qui passe par ces points (on en connaît les coordonnées : x_i et y_i). Au lieu d’utiliser une régression linéaire, on peut passer par de la programmation probabiliste. Une droite, en deux dimensions, est déterminée par deux paramètres (une pente et une intersection avec l’un des axes, par exemple). Pour comparer le modèle aléatoire aux données, il faut calculer les coordonnées de points : on connaît les x_i, on détermine les y_i selon les paramètres tirés aléatoirement ; après, on comparera ces y_i aux vraies valeurs. La fonction génératrice ressemble alors à une fonction Julia normale, mais annotée avec @gen (de même, chaque variable aléatoire est annotée avec @trace) :

Code :
1
2
3
4
5
6
7
8
9
10
@gen function line_model(xs::Vector{Float64})
    slope = @trace(normal(0, 1), :slope)
    intercept = @trace(normal(0, 2), :intercept)
     
    for (i, x) in enumerate(xs)
        @trace(normal(slope * x + intercept, 0.1), (:y, i))
    end
     
    return length(xs)
end
Ensuite, on peut effectuer de l’inférence (ici, en tirant au hasard des valeurs cent fois — un procédé très cru, pas forcément rapide, mais facile à implémenter et comprendre !) :

Code :
1
2
3
4
5
6
7
8
9
xs = [-5., -4., -3., -.2, -1., 0., 1., 2., 3., 4., 5.]
ys = [6.75003, 6.1568, 4.26414, 1.84894, 3.09686, 1.94026, 1.36411, -0.83959, -0.976, -1.93363, -2.91303]
 
observations = Gen.choicemap()
for (i, y) in enumerate(ys)
    observations[(:y, i)] = y
end
 
(trace, _) = Gen.importance_resampling(model, (xs,), observations, 100)
En répétant l’expérience un certain nombre de fois, on trouve une série de droites qui expliquent au mieux, pour chaque centaine de tentatives, les données :


Après cette inférence, Gen a appris la densité la plus probable des paramètres de la ligne : il peut ensuite générer de nouveaux points, grâce à ce qu’il a enregistré, en utilisant la fonction Gen.generate.


La différence entre Gen et d’autres systèmes de programmation probabiliste est sa nature universelle : le système peut être utilisé pour n’importe quelle tâche de programmation probabiliste (même si cet article se focalise sur l’inférence a posteriori). L’implémentation est prévue pour être facile à adapter à ses propres besoins (on peut écrire son propre moteur d’inférence, même s’il en existe déjà un certain nombre). Jusqu’à présent, les systèmes probabilistes disposaient soit de bonnes capacités d’inférence (mais une modélisation limitée), soit au contraire étaient aussi généralistes, mais sans algorithme d’inférence performant. Gen renverse la donne, en étant universel, mais aussi en incluant une grande variété de possibilités d’inférence.

Source : Gen: a general-purpose probabilistic programming system with programmable inference. L’exemple développé provient de la documentation de Gen.

Voir aussi : le code source de Gen.
  Discussion forum
2 commentaires
  • gallima
    Membre averti
    Cela me fait un peu penser à Problog un langage probabiliste (inférence bayésienne) basé sur Prolog.
  • SQLpro
    Rédacteur
    l'algorithme sous-jacent est vieux comme le monde, c'est la "méthode de Monte-Carlo" !