![]() |
(Source: Wikimedia) |
Version courte pour lecteur pressé
Happé par une (légère) obsession, votre humble serviteur s’est lancé dans la
fabrication d’un générateur de texte algorithmique simpliste qu’il a baptisé
Laverdure en hommage à Raymond Queneau. Aucune trace d’intelligence
artificielle ici ; le truc pond des phrases telles que : « Le prestige à nos
souples machines au nord de tatouages prélevés sur l’atlantique
[sic]. »
Ce billet explique la genèse et le fonctionnement de ce projet de
programmation récréatif. Mais peut-être avez-vous autre chose à faire de
votre soirée ?
L’histoire d’une idée
C’était il y a longtemps. Je venais d’obtenir mon baccalauréat en
informatique et j’avais la vague ambition de vouloir poursuivre mes études
universitaires. Je me suis donc inscrit à la maîtrise et j’ai passé quelque
temps au laboratoire d’intelligence artificielle à plancher sur un modèle de
langage programmé en
Prolog. À
l’époque, on tentait encore de modéliser les éléments de la langue à partir
du lexique, de la syntaxe et de la sémantique. Rien à voir avec l’approche
actuelle qui laisse l’apprentissage profond inférer et calquer les
propriétés de la langue (à la
ChatGPT et compagnie).
C’était la fin des années 1980 et l’informatique n’était pas tout à fait ce
qu’elle est aujourd’hui ; il s’agissait d’une discipline encore jeune et sur le
point de connaître des avancées techniques spectaculaires. Ces révolutions à
venir découleraient souvent de connaissances théoriques alors déjà connues
(1).
J’ai eu bien du plaisir à programmer en Prolog sur une
station Sun en
écoutant le premier album de Noir Désir. Je n’ai cependant jamais vu le bout
de ce projet, comme je n’ai jamais vu le bout de ma maîtrise. J’ai quitté
l’université et me suis trouvé un emploi. Je poursuis depuis ce que je n’ai
jamais osé appeler une carrière en informatique. Dans un univers
parallèle, j’aurais marié ma passion de l’informatique à celle de la
littérature, et j’aurais poursuivi des études supérieures à fouiller la
question de la génération du texte. Peut-être serais-je aujourd’hui à la
fine pointe du développement des modèles de langages ? Mais cet univers
parallèle ne s’est pas avéré et j’ai continué mon chemin
sur la route pleine d’embranchements et d’événements aléatoires que fut
ma vie.
C’est en lisant des articles sur le fonctionnement des modèles de langue
dernier cri (tel que ChatGPT) que j’ai eu l’idée d’un algorithme simpliste
qui permettrait de générer du texte sans avoir à s’en faire avec les
considérations syntaxiques et sémantiques.
C’est que lorsqu’il génère du texte, ChatGPT le fait un mot à la fois, en
évaluant à chaque étape quel est le mot le plus probable (je
simplifie) permettant de poursuivre la conversation. La façon de déterminer
ce mot met à profit un modèle très complexe construit sur un gigantesque
réseau neuronal (etc.).
Je me suis dit qu’il y aurait moyen de faire quelque chose de vaguement
semblable en utilisant un simple tableau des séquences de deux mots contigus
dans un corpus. On lit du texte, on compile la fréquence de chaque suite de
deux mots, puis, à partir de ces données, on génère du texte. Par exemple,
après le mot obsolescence, le programme serait porté à écrire un mot
qu’on voit (trop) souvent ensuite, programmée par exemple. J’ai
eu l’intuition que cet algorithme permettrait de conserver des traces de la
syntaxe française et donnerait de meilleurs résultats que de simplement
choisir des mots au hasard. (2)
Cette idée est vite devenue une obsession et pour m’en libérer, je me suis
lancé dans un petit projet de programmation. Cet article vous présente les
résultats de ce projet récréatif, que j’ai baptisé
Laverdure, le perroquet stochastique.
Pourquoi ce nom ?
Le nom de Laverdure est un hommage à Raymond Queneau. Dans son roman
Zazie dans le métro, Queneau met en scène un perroquet appelé Laverdure, qui répète souvent la
formule « Tu causes, tu causes, c’est tout ce que tu sais faire ». (3)
J’ai volé la formule « perroquet stochastique » à l’article
On the Dangers of Stochastic Parrots: Can Language Models Be Too
Big?
de Emily M. Bender, Timnit Gebru et autres. Cet article fort pertinent décrit les risques associés aux
modèles contemporains de langage par apprentissage profond.
Stochastic Parrot est devenu une expression consacrée dans le joyeux
monde des générateurs de langage et de l’intelligence artificielle. (4)
Ce que Laverdure sait faire
Le programme Laverdure a deux fonctions principales.
- Il analyse des fichiers de texte et compile un corpus simple des unités lexicales qu’il y découvre.
- En utilisant ce corpus, il génère du texte un mot à la fois selon divers algorithmes simplistes.
Les unités lexicales et le corpus
Laverdure peut découper un texte en unités lexicales, que j’appellerai ici
token (5).
Pour Laverdure, un token est soit un mot, soit un groupe de mots reliés par
un signe (comme l’apostrophe ou le trait d’union), soit une ponctuation. Le
fait de considérer les signes de ponctuation comme des tokens permettra au
générateur de texte d’insérer des ponctuations de façon naturelle, par
exemple, de faire en sorte que le mot mais soit généralement précédé d’une
virgule. Cela permettra aussi de former des phrases en insérant des points
de temps à autre.
Pour Laverdure, un corpus est formé de deux ensembles : d’abord la liste des
tokens rencontrés et leur fréquence, et ensuite la liste des couples de
tokens adjacents et leur fréquence.
On peut demander à Laverdure de créer un nouveau corpus à partir d’un
fichier de texte. Il peut aussi sur demande ajouter un fichier de texte à un
corpus existant. On peut aussi interroger Laverdure à propos du contenu du
corpus.
Par exemple, ci-après, le corpus créé à partir du texte du roman
Vingt Mille Lieues sous les mers de Jules Verne, obtenu du site du
projet Gutenberg.
Nombre de fichiers de texte: 1
20000_lieues_sous_les_mers (153297 mots)
Nombre de mots dans le texte brut: 153297
Nombre de tokens uniques:
15822
Nombre de couples uniques: 70637
On constate que le roman comporte 153 297 tokens, dont 15 822 tokens
uniques. Ces tokens forment 70 637 couples différents (séquences distinctes
de deux tokens).
Si on interroge Laverdure à propos du token « poulpe », par exemple, on
découvre qu’il y a 9 occurrences de ce mot dans le texte du roman, et 5 couples débutant avec ce mot (je rappelle que les ponctuations, comme le
point et la virgule, sont aussi des tokens).
token="poulpe" n=9
("poulpe", ".") n=3
("poulpe", ",") n=3
("poulpe", "en") n=1
("poulpe", "sur") n=1
("poulpe", "calmar") n=1
Notons au passage que Vingt Mille Lieues sous les mers ne
comporte aucune occurrence du mot « pieuvre » (6), trois fois le mot «
Québec » et une fois le mot « Canada ».
Voici un autre exemple de ce que contient le corpus de ce roman. Le mot « navire » apparaît 78 fois. Voici la liste de chaque token qui suit le mot « navire » et, pour chacun, le nombre d’occurrences.
token="navire" n=78
("navire", "!") n=2
("navire", ".") n=9
("navire", ",") n=17
("navire", "de") n=3
("navire", "et") n=1
("navire", "à") n=1
("navire", "se") n=2
("navire", "dont") n=1
("navire", "par") n=1
("navire", "en") n=3
("navire", "comme") n=1
("navire", "que") n=2
("navire", "qui") n=7
("navire", "?") n=6
("navire", "d'une") n=1
("navire", "n'avait") n=1
("navire", "était") n=1
("navire", "dans") n=1
("navire", "abandonné") n=1
("navire", "n'a") n=1
("navire", "avance") n=1
("navire", "tel") n=1
("navire", "résisterait") n=1
("navire", "moderne") n=1
("navire", "destiné") n=1
("navire", "construit") n=1
("navire", "ordinaire") n=1
("navire", "engagé") n=1
("navire", "submergé") n=1
("navire", "naviguait") n=1
("navire", "flottait") n=1
("navire", "s'enfonça") n=1
("navire", "l'argonaute") n=1
("navire", "cuirassé") n=1
("navire", "patriote") n=1
("navire", "insensé") n=1
Un corpus qui peut faire boule de neige
Laverdure peut additionner les données de plusieurs fichiers de texte dans
le même corpus. Par exemple, si on ajoute aux données de
Vingt Mille Lieues sous les mers le texte du roman
Notre-Dame de Paris de Victor Hugo (aussi obtenu par le biais du site
du projet Gutenberg), notre corpus prend de l’ampleur.
Nombre de fichiers de texte: 2
20000_lieues_sous_les_mers (153297 mots)
Notre-Dame_de_Paris (198713 mots)
Nombre de mots dans le texte brut: 352010
Nombre de tokens uniques:
27501
Nombre de couples uniques: 147579
Allez, pourquoi ne pas ajouter le texte du roman Germinal d’Émile Zola
(toujours tiré de Gutenberg) ? Voici les statistiques de la combinaison de
ces trois romans.
Nombre de fichiers de texte: 3
20000_lieues_sous_les_mers (153297 mots)
Notre-Dame_de_Paris (198713 mots)
Germinal (198341 mots)
Nombre de mots dans le texte brut: 550351
Nombre de tokens uniques:
33835
Nombre de couples uniques: 207000
Des 550 351 tokens que totalisent ces 3 romans, Laverdure a extrait 33 835 tokens uniques et 207 000 (tout rond !) séquences de 2 tokens. Dans ce
corpus, on trouve toujours 9 fois « poulpe », mais aussi 246 occurrences de
« Quasimodo » (hé, hé).
Allez, ajoutons Les trois mousquetaires d’Alexandre Dumas. Et vive le projet Gutenberg.
Nombre de fichiers de texte: 4
20000_lieues_sous_les_mers (153297 mots)
Notre-Dame_de_Paris (198713 mots)
Germinal (198341 mots)
Les_Trois_Mousquetaires (259601 mots)
Nombre de mots dans le texte brut: 809943
Nombre de tokens uniques:
40165
Nombre de couples uniques: 272124
Dans ce corpus, le token « le » apparaît 16 918 fois, « neige » 34 fois,
mais — sans surprise — on n’y trouve aucune fois le mot « logiciel » (vous
pouvez me croire sur parole).
Les algorithmes de génération de texte
À partir de cette structure de données, j’ai bidouillé quelques algorithmes
simples de génération de texte.
Mettez ça sur le compte de mon esprit cartésien, mais le texte généré de
façon purement aléatoire ne m’a jamais satisfait ; ces jeux oulipiens
montrent vite leurs limites et l’écriture automatique m’ennuie. Comme je le
disais plus haut, j’espérais que les probabilités et la mémoire des paires
de mots contigus tirés du corpus viennent mettre un peu d’ordre dans le
hasard.
Voici le résultat de mes expériences. (Les résultats produits par Laverdure
sont présentés tels que générés; tous les mots, y compris les noms propres,
sont en minuscule, sauf lorsqu’ils sont au début d’une phrase.)
Un mot au hasard
Commençons avec le degré zéro de la génération de texte : tirons des mots au
hasard dans le corpus.
Voici un texte de cent mots tirés au hasard de Notre-Dame de Paris.
Puante baladins arrivèrent alentour charnue hier d'anges l'insouciant
ventre-mahom agissaient maçons garçon époque savourait expirèrent scènes
equitem syriaque défaille ta charretiers d'embas l'incartade rondes
l'admirable colosse saviez devrait battante conformément oscillations
ressembler eussiez entr'ouvrit concierge appuis symbolisme imprimer
patente voyage humeur chargés passeraient sifflantes saint-jean-le-rond
boulangerie l'ave figures cyprin surtout détournaient erras justement
mariait disponibles clémente d'îles parts assiégés dépité haletait mur
sifflèrent adroitement charnier palestrina mannequin lentement d'ennemis
luminaire persistez-vous mort ajouté hoctement marie alternative
s'enfermait ineffables heureux rira sub jettent somptuosité septentrion
soif l'écoutait cherché raison tournaient stryga conduits figura route
chat d'amis ondulait dignes pieds écriée deuxièmement
On s’y attendait, les résultats sont aléatoires et inintéressants. Le seul
intérêt vient du lexique du roman (ventre-mahom, embas,
syriaque, les bribes de
latin, etc.). Aussi, puisqu’il y a plus de 90 000 tokens uniques dans le
corpus, avec cet algorithme, la probabilité de tirer une ponctuation est
très faible, et le texte s’étire par conséquent en une longue phrase
incohérente et en apparence infinie.
Un des mots suivants au hasard
Tentons de tirer profit de l’information de notre corpus. Après avoir ajouté
un mot au texte, tirons un token au hasard parmi les tokens suivants
répertoriés pour ce mot.
Voici ce que ça donne en utilisant Notre-Dame de Paris comme source. Le
texte compte un peu plus de cent mots et débute par le mot « La ».
La monstrueuse bête en perspective que d'avoir de sanctuaire du
brouillard faisait attendre au fripier qui portait en s'aidant seulement
tout. Philippe-auguste qu'on vous garde bien quoi payer. Rends-les tous
les découpures d'une croix d'argent à boucle de mahom en seconde avait
entassé le contre-guet la période, répandues en 64. Allons essayer
d'indiquer, tour près et s'adressant à une condition sans s'occuper du
greffe pour ce gros eustache eût hasardé cette sœur gudule ! Réflexion fut
obligé, hermès. Pasquedieu ! Plaudite, on pouvait dissimuler sa phrase,
madamoiselle de s'arrêter sous tant dit tristan avait alors tu cessas de
baladin.
C’est déjà un peu mieux. Le texte est rythmé de ponctuations et on aperçoit
ici et là quelques séquences qui se tiennent sur le plan de la syntaxe (« une croix d’argent à boucle de Mahom », « sans s’occuper du greffe pour ce
gros Eustache », « on pouvait dissimuler »).
Un mot suivant fréquent ou au hasard (alias mode optimisé)
Je me suis ensuite dit qu’il y aurait moyen d’améliorer la qualité du texte
en favorisant les mots suivants les plus fréquents selon les données du
corpus.
J’ai d’abord essayé, pour chaque mot ajouté au texte, de choisir le token
adjacent le plus fréquent, mais ce genre d’algorithme déterministe finit
souvent par produire du texte qui se répète en boucle.
En guise de compromis, j’ai inventé ce que j’ai présomptueusement baptisé le
mode optimisé. Ça consiste à choisir chaque prochain mot comme suit :
- selon une certaine probabilité (par exemple 60 %), on choisit au hasard parmi tous les tokens suivants répertoriés ;
- sinon, on choisit parmi une certaine proportion (30 % par exemple) des tokens suivants les plus fréquents.
Cet algorithme a l’avantage de favoriser les tokens suivants plus fréquents,
mais aussi de se soumettre au hasard, ce qui génère plus de variété et évite
les boucles.
Voici ce que ça donne, toujours avec Notre-Dame de Paris et en débutant par le mot « La ».
La meute y allume des marches de bimbeloterie qui sautaient en magie ?
Tout paris n'est rien dire qu'il paraissait avoir suivi de mer agitée.
C'étaient vingt francs pour cet art-roi, tremblant de douceur infinie : il
retombait dans l'air très redouté cardinal on dirait, faute de chien.
Faites là ? Ne s'était révélé ainsi : compère coppenole. J'allais.
Mort-christ ! Répéta la plupart des filles et jardins, aux
saints-innocents, pendaison de justice pour des halles, smelarda,
gendarmes, silence et sifflantes, mais dès l'âge de solide que venait se
condamne, monstre !
Le résultat n’est pas significativement supérieur à l’algorithme de la
section précédente, qui choisissait au hasard parmi les mots suivants. À
l’usage, il m’a semblé que j’obtenais des résultats généralement un peu
meilleurs avec cet algorithme, mais il est possible aussi que ce soit de
l’autosuggestion.
Voici un autre exemple, un texte d’un peu moins de 200 mots généré par cet
algorithme en utilisant le corpus géant formé par
Vingt Mille Lieues sous les mers, Notre-Dame de Paris,
Germinal et Les trois mousquetaires. Le mot initial a été
choisi au hasard.
Injuriait. L'ordre des syllabes, pourrait être muet de gazette des
jurements, s'installèrent. Cornemahom ! Laissez tomber sans boire ?
J'hésitais à petites taches très-rares. L’air des affaires vont,
déchiqueté par 55° de visites que l'emprosthotonos succède à l'un sert à
armentières, tellement alourdis de festubert, l'espoir mort en revanche de
renoncer à quoi la même idée aussi parce qu'en devenant plus bien,
entassés, hermès, requins, s’interpellant, nom d'encornets, certes,
ébranlé. Qu'allais-tu faire en grande ouverte établissait par l’hôte avait
posé ce navire se fournissaient une lime, prévenu de naissance inconnue.
Mademoiselle ! Sans quelques mouvements que marie eût bien tranquillement,
celles d'yves, poussé adroitement à apitoyer. Va-t'en donc comme
l'agamemnon de monstres vaincus, tenue la ressaisir son effroi se retenir,
sillonnés de celui-ci les brasiers. Vainement d'emprunter dix jours plus
travailler ? Faisons feu succéda la nouvelle-zemble ? J’en use et choir !
M'écriai-je. N'est-ce donc pour s'en adoucit, dense, là-bas sa moustache
noire sur pilotis, pouvaient faire du navire cuirassé d'argent !
Gueulait-il. Bon frère zacharie ! Quiconque porte pour l'atteindre de
popeline gros qui s'enfonce suivant cassiodore, répandirent bientôt à tous
vu.
(Vous ne serez pas surpris si je vous dis que le mot « agamemnon » provient
de Notre-Dame de Paris, et que « par 55° » est tiré de
Vingt Mille Lieues sous les mers.)
En définitive, on a beau tenter d’optimiser le choix du prochain mot parmi
les mots suivants répertoriés, l’algorithme n’a qu’une vision circonscrite
du texte qu’il génère. Ça n’assure la cohérence (ou une possible cohérence)
que d’un couple de mots à la fois. Le pauvre programme marche en regardant
le bout de ses pieds. Si des caractéristiques syntaxiques ou sémantiques
d’un mot peuvent être conservées dans le suivant (par exemple, un article au
pluriel sera probablement suivi par un substantif au pluriel), elles ne le
sont pas au-delà. À l’échelle de la phrase, la cohérence syntaxique tiendra
donc du pur hasard ; le fait par exemple qu’après un substantif au pluriel,
trois mots plus loin, on pige un verbe à la troisième personne du pluriel.
Quand on se limite à une seule phrase, et par essais et erreurs, on peut
produire des bouts de texte possédant un certain potentiel d’évocation. J’ai
publié
dans mon compte quoli.bet (qui, en quelque sorte, remplace maintenant mon ancien compte touitteur @nanopoesie) quelques quatrains composés de phrases ainsi créées par Laverdure (7).
Conclusion
Quelques réflexions pour conclure.
Les tendances actuelles de l’intelligence artificielle générative impliquent
de créer des corpus gigantesques composés de contenus souvent protégés par
le droit d’auteur et sans obtenir la permission préalable des
créateurs.
Malgré la nature privée de mon projet, il m’a semblé important que le corpus
comporte un minimum d’information sur les documents qui le composent.
Je me suis limité à répertorier le nom des fichiers, mais j’ai imaginé
d’autres stratégies, comme l’ajout de métadonnées concernant les textes
(auteurs, édition, etc.). J’ai aussi eu l’idée de stocker les données de
fréquence de telle manière qu’on puisse les rattacher au texte d’origine.
Cela permettrait d’interroger les statistiques propres à une œuvre du
corpus (et non pas de l’ensemble) ; cela permettrait aussi de retirer la
partie du corpus provenant d’une œuvre donnée. Je ne me suis cependant pas
lancé dans ces projets dans le projet.
Par ailleurs, j’ai remarqué qu’il est intéressant d’utiliser un corpus tiré
d’une unique œuvre de grande taille (comme un roman). Ça favorise
l’uniformité du champ lexical, du style et des temps de verbe, notamment.
Lorsqu’on génère du texte à partir d’une seule œuvre, on obtient une espèce
de remix ou de collage (en anglais, on dirait mashup) dans lequel on
reconnaît des traces du texte d’origine (ce qui donne tout son sens au
concept de perroquet). Vingt Mille Lieues sous les mers de Jules
Verne s’est avéré en cela un excellent corpus, avec son vocabulaire
technique, propre aux choses maritimes et sous-marines.
En fin de compte, si ce projet de programmation fut une source de
récréation, les résultats sont loin d’être satisfaisants et je me suis vite
lassé de mon petit programme. Il me semble pour le moment avoir tiré tout le
jus de ce concept. Laverdure va donc demeurer sagement planqué au fond du disque dur de mon ordinateur.
Ne restera que ce billet de blogue pour témoigner de l’existence éphémère de
Laverdure, mon perroquet stochastique.
*
Notes :
(1) Par exemple, les langages de programmation dits orientés-objet, les
bases de données relationnelles, les microprocesseurs à architecture RISC,
la réseautique TCP/IP, et même les réseaux neuronaux.
(2) J’ai ensuite lu
cet article de blogue de Stephen Wolfram, le mythique inventeur du logiciel Mathematica ; les deux premiers
chapitres expliquent ce qu’un programme simple comme Laverdure tente de
faire et en quoi les réseaux neuronaux sont infiniment supérieurs.
(3) Laverdure est un des nombreux
personnages de perroquet dans la littérature.
(4) Précisons tout de suite que Laverdure est un programme algorithmique
et naïf qui ne compte que quelques centaines de lignes de JavaScript, et qu’il n’a rien d’une intelligence artificielle.
(5) Lorsque je bricole de petits programmes personnels, j’utilise
naturellement le français pour les variables et les commentaires
explicatifs insérés dans le texte des programmes. Il m’arrive aussi
parfois, par économie et pour me comprendre moi-même, d’utiliser des mots
anglais consacrés. D’où ce token.
(6) Le mot
pieuvre a été popularisé par Victor Hugo
dans son roman Les travailleurs de la mer publié en 1866, à partir
d’un mot du vieux normand en usage à Guernesey. Il semble que Verne, qui a
publié Vingt Mille Lieues sous les mers à la même époque, soit en
1869, n’ait pas subi cette influence.
(7) quoli.bet est un réseau social fort sympathique, patenté fort professionnellement par David Turgeon et connecté au Fedivers.