Logo Blog perso d'Ozwald

CamemBERT

Par Oz le - misc
I.A. python

Parmi les domaines qui bougent beaucoup en ce moment, on ne peut pas passer à côté de l'intelligence articifielle. Les avancées théoriques et pratiques sont tellement rapides dans le domaine que, presque à chaque fois que je me repenche dessus, je suis abasourdi par les nouveautés disponibles. J'en veux pour exemple les avancées récentes dans la manipulation de langues écrites. Il y a encore 10 ans, aucune machine ne pouvait se targuer de comprendre ou de générer du texte correctement. Aujourd'hui, plusieurs réseaux de neurones sont capables de comprendre des textes, de les résumer, voire d'en générer de plutôt convaincants à partir de "rien" !

"Camembert" - CC BY SA by "Steven Lilley" on Flickr

Et le plus fort dans tout ça, c'est qu'il est possible de télécharger des réseaux pré-entrainé a priori très convaincants. J'ai longtemps hésité à me jeter sur un réseau GPT2 (qui semble être ce qui se fait de mieux en génération) ou sur un réseau BERT (qui semble être ce qui se fait de mieux pour du traitement de langage écrit polyvalent : compréhension, résumé, génération, etc.) puis j'ai trouvé un réseau BERT qui avait été entrainé en français. Comme j'aime bien jouer en français, notamment pour le traitement du langage, j'ai donc jeté mon dévolu sur cette option.

Installer le réseau de neurones

Le réseau en question s'appelle camemBERT et est disponible librement. Cependant, comme souvent dans ce domaine de l'informatique à la pointe de la recherche, on va devoir installer beaucoup de dépendances dans des versions très récentes1, pour le faire fonctionner. Je recommande donc vivement d'utiliser un environnement virtuel Python si vous souhaitez conserver un système stable :

user@oziris:~$ python3 -m venv camembert.venv
user@oziris:~$ source camembert.venv/bin/activate

Maintenant qu'on est dans un environnement virtuel un minimum cloisonné, regardons ce par quoi le tutoriel va commencer :

import torch
camembert = torch.hub.load('pytorch/fairseq', 'camembert')
camembert.eval()  # disable dropout (or leave in train mode to finetune)

Logiquement, ça commence par un import de torch. À moins que vous n'ayez déjà installé PyTorch dans votre environnement global, il va donc falloir l'installer dans notre environnement virtuel :

(camembert.venv) user@oziris:~$ # D'abord, on vérifie que, effectivement, on n'a pas installé PyTorch précédemment :
(camembert.venv) user@oziris:~$ python3 -c 'import torch'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'torch'
(camembert.venv) user@oziris:~$ # Maintenant qu'on est fixé, on commence à peupler notre environnement virtuel
(camembert.venv) user@oziris:~$ pip install torch  # Et oui : le paquet "pytorch" s'appelle "torch"...
Collecting torch
(...)
Installing collected packages: typing-extensions, numpy, torch
Successfully installed numpy-1.20.0 torch-1.7.1 typing-extensions-3.7.4.3

On voit que, en plus de PyTorch, on s'est pris numpy et typing-extensions. On a bien fait de se mettre dans un environnement séparé du système. Donc, l'import de torch ne remonte plus d'erreur maintenant, c'est bon signe :

(camembert.venv) user@oziris:~$ python3 -c 'import torch' && echo "Victoire"
Victoire

On peut passer à la seconde ligne du tutorial qui semble être le (télé)chargement du réseau de neurone CamemBERT :

>>> import torch
>>> camembert = torch.hub.load('pytorch/fairseq', 'camembert')
(...)
RuntimeError: Missing dependencies: hydra-core, omegaconf, regex, requests

Visiblement, il nous manque quelques dépendances. Qu'à cela ne tienne, on est dans un environnement jetable exprès donc on peut se permettre d'ajouter pleins de librairies plus ou moins instables :

(camembert.venv) user@oziris:~$ pip install hydra-core omegaconf regex requests
(...)
ModuleNotFoundError: No module named 'sentencepiece'
(...)
ImportError: Please install sentencepiece with: pip install sentencepiece

Encore un p'tit module qui manque. Pas grave, on l'ajoute :

(camembert.venv) user@oziris:~$ pip install sentencepiece
(...)
    ./build_bundled.sh: 15: ./build_bundled.sh: cmake: not found
    make: *** Pas de cible spécifiée et aucun makefile n'a été trouvé. Arrêt.
    make: *** Aucune règle pour fabriquer la cible « install ». Arrêt.
    env: « pkg-config »: Aucun fichier ou dossier de ce type
    Failed to find sentencepiece pkg-config
(...)

Okay, mon mauvais2, je réalise cet article sur une Debian stable et j'ai visiblement trop l'habitude d'être sur Gentoo où tous les outils de compilation du monde sont forcément installés. Il me manque cmake et pkg-config, donc je répare cet oubli (en installant cmake et pkg-config au niveau de mon système, donc on déborde de l'environnement virtual python là) puis je re-lance l'installation de sentencepiece dans l'environnement virtuel :

root@oziris:~# apt install cmake pkg-config
(...)
(camembert.venv) user@oziris:~$ pip install sentencepiece
(...)
Successfully installed sentencepiece-0.1.95

Ça s'est plutôt correctement passé, on peut donc revenir au tutoriel et tenter, à nouveau de (télé)charger le réseau camemBERT :

>>> import torch
>>> camembert = torch.hub.load('pytorch/fairseq', 'camembert')
(...)
[...]camembert.venv/lib/python3.7/site-packages/torch/cuda/__init__.py:52: UserWarning: CUDA initialization: Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed a driver from http://www.nvidia.com/Download/index.aspx (Triggered internally at  /pytorch/c10/cuda/CUDAFunctions.cpp:100.)
  return torch._C._cuda_getDeviceCount() > 0
Unable to build Cython components. Please make sure Cython is installed if the torch.hub model you are loading depends on it.

Installer CUDA

Cette fois il y a un minuscule piège : le message d'erreur qui apparait en dernier n'est pas le bon. En effet, j'ai déjà cython installé dans mon système, mais pas encore Cuda. Là aussi, on va déborder de l'environnement virtuel python et on va installer des paquets systèmes (en suivant les instructions officielles :

root@oziris:~# apt install nvidia-cuda-dev nvidia-cuda-toolkit
(...)
Après cette opération, 2 534 Mo d'espace disque supplémentaires seront utilisés.
Souhaitez-vous continuer ? [O/n]
(...)
update-initramfs: Generating /boot/initrd.img-***censored*** 
gzip: stdout: No space left on device 
E: mkinitramfs failure cpio 141 gzip 1
update-initramfs: failed for /boot/initrd.img-***censored*** with 1.
dpkg: erreur de traitement du paquet initramfs-tools (--configure) :
 installed initramfs-tools package post-installation script subprocess returned error exit status 1
Des erreurs ont été rencontrées pendant l'exécution :
 initramfs-tools
E: Sub-process /usr/bin/dpkg returned an error code (1)

On pourrait croire que ce sont les 2,5Go de paquets qui posent problème mais pas du tout. C'est ma partition /boot qui est pleine :

root@oziris:~# df -h|grep boot
/dev/***censored***            236M    202M   22M  91% /boot

Heureusement, ce problème et ses solutions semblent bien documentées sur debian-like. Dans mon cas un simple apt autoremove suffira.

root@oziris:~# apt autoremove && df -h|grep boot
/dev/***censored***            236M    110M  114M  50% /boot

On peut donc relancer l'installation de Cuda, constater qu'on ne prend plus l'erreur, et retourner au tutorial :

>>> import torch
>>> camembert = torch.hub.load('pytorch/fairseq', 'camembert')
[...]camembert.venv/lib/python3.7/site-packages/torch/cuda/__init__.py:52: UserWarning: CUDA initialization: The NVIDIA driver on your system is too old (found version 10010). Please update your GPU driver by downloading and installing a new version from the URL: http://www.nvidia.com/Download/index.aspx Alternatively, go to: https://pytorch.org to install a PyTorch version that has been compiled with your version of the CUDA driver. (Triggered internally at  /pytorch/c10/cuda/CUDAFunctions.cpp:100.)
  return torch._C._cuda_getDeviceCount() > 0
Unable to build Cython components. Please make sure Cython is installed if the torch.hub model you are loading depends on it. 

Forcément. J'avais déjà eu ce problème à chaque fois que je faisais du CUDA (et plus particulièrement sur Debian) : les drivers évoluent vite et abandonnent rapidement la rétro-compatibilité. Avant de se lancer dans une course à la mise à jour (puisqu'on est hors environnement virtuel et que je veux conserver un système stable) on peut vérifier les versions de CUDA et de PyTorch qu'on a installé puis chercher si, à tout hasard, une version de pytorch relativement récente serait compatible. En faisant ça, je réalise que, pour une version de PyTorch donné, il existe parfois plusieurs paquets différents pour être compatible avec des versions différentes de CUDA. Cool ! Je tente donc d'installer la dernière version de PyTorch, mais compatible avec le CUDA 9.2 que j'ai installé sur ma debian stable :

root@oziris:~# apt show nvidia-cuda-dev 2>/dev/null|grep Version  # On vérifie la version de CUDA qu'on a
Version: 9.2.148-7
(camembert.vent) user@oziris:~$ pip freeze|grep torch  # On vérifie la version de PyTorch qu'on avait
torch==1.7.1
(camembert.vent) user@oziris:~$ pip uninstall torch
(...)
(camembert.vent) user@oziris:~$ pip install torch==1.7.1+cu92 -f https://download.pytorch.org/whl/torch_stable.html
(...)
Successfully installed torch-1.7.1+cu92

Tester CamemBERT

On re-tente le tutorial en espérant que, cette fois, le (télé)chargement de camemBERT va bien se passer et qu'on va pouvoir taper le 3ème ligne du tutorial :

>>> import torch
>>> camembert = torch.hub.load('pytorch/fairseq', 'camembert')
Using cache found in /home/user/.cache/torch/hub/pytorch_fairseq_master
Unable to build Cython components. Please make sure Cython is installed if the torch.hub model you are loading depends on it.
>>> masked_line = 'Le camembert est <mask> :)'
>>> camembert.fill_mask(masked_line, topk=3)
[('Le camembert est délicieux :)', 0.49091005325317383, ' délicieux'), ('Le camembert est excellent :)', 0.10556904226541519, ' excellent'), ('Le camembert est succulent :)', 0.0345332995057106, ' succulent')]

YEAH ! On a un camembert qui fonctionne3. En résumé : on lui donne un texte avec un trou représenté par <mask>, et il nous répond avec des propositions pour remplir le trou. Comme on peut le voir ci-dessus, ces propositions sont plutôt très pertinentes. Maintenant qu'on a réussi à reproduire l'exemple du tuto, on peut jouer avec de pleins de façons différentes. Par exemple en vérifiant ce qu'il pense de différents smileys :

>>> import torch
>>> camembert = torch.hub.load('pytorch/fairseq', 'camembert')                          
>>> camembert.fill_mask('Le camembert est <mask> :-)')[0][0]
'Le camembert est délicieux :-)'
>>> camembert.fill_mask('Le camembert est <mask> :-/')[0][0]
'Le camembert est introuvable :-/'
>>> camembert.fill_mask('Le camembert est <mask> :-(')[0][0]
'Le camembert est introuvable :-('

C'est plutôt pas mal du tout cette histoire ! CamemBERT a bien réalisé que ce qui était après le "trou" avait changé, et il en a déduit un bouche-trou plus pertinent. Il faut savoir qu'une des forces des réseaux BERT, c'est de prendre en compte du contexte avant et apres un mot (ou un trou) considéré. On peut donc tenter de modifier également ce qu'il y a en début de phrase. Par exemple, vérifions comment il réagit lorsqu'on modifie légèrement le sujet :

>>> camembert.fill_mask('Le gros camembert est <mask> :-)')[0][0]
'Le gros camembert est arrivé :-)'
>>> camembert.fill_mask('Le petit camembert est <mask> :-)')[0][0]
'Le petit camembert est délicieux :-)'
>>> camembert.fill_mask('Le gros camembert est <mask> :-(')[0][0]
'Le gros camembert est arrivé :-('
>>> camembert.fill_mask('Le petit camembert est <mask> :-(')[0][0]
'Le petit camembert est délicieux :-('
>>> camembert.fill_mask('Le petit bateau est <mask> :-(')[0][0]
'Le petit bateau est mort :-('
>>> camembert.fill_mask('Le petit bateau est <mask> :-)')[0][0]
'Le petit bateau est arrivé :-)'

Tout n'est pas comme on aurait pu l'imaginer, mais rien de toute ceci ne semble totalement délirant (après tout, il a le droit d'être légitimement heureux et triste que le "gros camembert" soit arrivé).

Et si on s'éloigne franchement de l'exemple du tuto, est-ce-que ça tient encore la route tout ça ?

>>> camembert.fill_mask('Bonjour mon cher <mask> !')[0][0]
'Bonjour mon cher ami !'
>>> camembert.fill_mask('Comment allez <mask> ?')[0][0]
'Comment allez vous ?'
>>> camembert.fill_mask("J'espère que vous <mask> bien.")[0][0]
"J'espère que vous allez bien."
>>> camembert.fill_mask("Que pensez-vous de cette belle <mask> ?")[0][0]
'Que pensez-vous de cette belle exposition ?'

Franchement bluffant...Mais ces phrases peuvent sembler assez "évidentes" et je soupçonne qu'un algo très con mais disposant d'un nombre de livres assez conséquent serait parvenu au même résultat. Voyons-voir ce qu'il se passe si on tend des pièges :

>>> camembert.fill_mask("Après une grosse journée de travail j'aime me <mask>.")[0][0]
"Après une grosse journée de travail j'aime me reposer."
>>> camembert.fill_mask("Avant une grosse journée de travail j'aime me <mask>.")[0][0]
"Avant une grosse journée de travail j'aime me détendre."
>>> camembert.fill_mask("J'aime la choucroute avec une bonne <mask>.")[0][0]  # Moins pertinent...BIERE !
J'aime la choucroute avec une bonne sauce."
>>> camembert.fill_mask("Hisser les voiles <mask>.")[0][0]  # Pardon ?
'Hisser les voiles sur.'
>>> camembert.fill_mask("Hisser les voiles <mask>!")[0][0]  # Pas mal.
'Hisser les voiles maintenant!'
>>> camembert.fill_mask("Hisser les voiles, <mask>!")[0][0]  # Décidément, je n'arriverai pas à avoir "moussaillons" :-p
'Hisser les voiles, bonjour!'

Conclusion

Même s'il n'est pas parfait, camemBERT est vraiment bluffant. Par contre, en décidant de partir sur un réseau BERT plutôt que sur un réseau GPT2 je n'avais pas anticipé un petit souci : le coeur de camemBERT est capable de beaucoup de choses (compréhension de texte notamment) mais, si on ne veut/peut pas mettre les mains dans le cambouis, on doit se contenter de ce qui est livré dans le tuto (à savoir le remplissage de texte à trou). Finalement, peut-être que jouer avec un GPT2 m'aurait donné accès à un "jouet" plus utile... Affaire à suivre ?

  1. Comprendre : très instables.
  2. Francisation à la hache de my bad
  3. Oui...cette phrase est étrange.

SAT solvers

Par Oz le - Sécurité
I.A. Outil SAT algo

Ce mois-ci je suis tombé, en moins de 24h, sur deux articles traitant de l'utilisation des SAT solvers dans un contexte de sécurité informatique. La (re)découverte de ces outils dans ce domaine m'a donné envie de partager l'expérience et je fais donc, via ce petit billet, un peu plus de "bruit google" autour des SAT solvers en espérant qu'ainsi quelqu'un d'autre passe un bon moment à (re)découvrir les possibilités de ces outils :)

Puzzle - Creative Common from a work by "INTVGene" on Flickr

Un "problème SAT" c'est un problème de décision visant à savoir s'il existe une solution à une série d'équations logiques données1. Résoudre un problème SAT revient donc à décider s'il existe, ou non, une configuration d'affectation "VRAI/FAUX" à des variables d'entrées qui permette de satisfaire une expression logique du type : "(condition1 OU condition2 OU ... OU conditionX) ET (conditionY OU...OU condition Y++) ET ... ET (...)". Par exemple si on considère deux variables de bool "A" et "B" on peut évaluer le problème SAT suivant "(A) ET (nonA)" qui n'a, évidemment, pas de solution et qui est donc "UNSATIFIABLE"; en revanche le problème SAT "(A ou B) ET (nonA ou B)" est SATISFIABLE avec, par exemple, les affectations : B=VRAI, A=VRAI. Un solveur SAT est un programme informatique dont la tache est de décider automatiquement si un problème SAT et UNSATISFIABLE ou SATISFIABLE (et de donner une solution exemple dans ce dernier cas de figure).

On trouve aujourd'hui beaucoup de logiciels de résolution SAT plutôt très efficace2 et on peut donc considérer que la technologie est assez mature pour jouer avec sans avoir à ramer dès l'installation ;) Par exemple "Minisat" est packagé dans toutes les bonne distributions Linux3 et vous n'aurez donc aucun souci à vous en procurer une version en état de marche.

Une fois un solveur SAT fonctionnel installé il faut apprendre quelques rudiments du langage "DIMACS". C'est un formalisme qui est utilisé pour représenter les problèmes SAT de façon compréhensible par 99% des solveurs publiques et qui, coup de chance, est basé sur du texte brute et reste super simple à apprendre :

  • Toute ligne commençant par un "c" sera considérée comme du commentaire
  • En début de fichier on doit renseigner le nombre de clauses (i.e. nombre de : "condition1 OU condition2 OU ...OU ... conditionX" ) ainsi que le nombre de variables que l'on va utiliser. Pour celà on écrit une ligne commençant par "p cnf" puis contenant les informations demandées. Au final la ligne ressemble à ça : "p cnf NOMBRE_DE_CLAUSE NOMBRE_DE_VARIABLES"
  • Ensuite on écrit, sur chaque ligne, une clause du problème dans laquelle on remplace : les variables par un numéro d'indice l'identifiant uniquement, les mots "OU" par des espaces, et les les "non" par des moins. On termine chaque ligne de clause par un "0" Ainsi notre problème SAT d'exemple UNSATISFIABLE ((A) ET (nonA)) devient4 :
p cnf 1 2
1 0
-1 0

De même notre second problème SAT d'exemple ((A OU B) ET (nonA OU B)) devient :

p cnf 2 2
1 2 0
-1 2 0

Quand on donne à manger le premier fichier texte à minisat on obtient bien UNSATISFIABLE, et quand on lui donne à manger le second on obtient SATISFIABLE sur la sortie standard et la solution exemple -1 2 0 dans le fichier de résultat5

Bon c'est bien joli, mais on ne va pas très loin avec ça me direz-vous ! Et bien si, justement :) ! Là où ça devient intéressant c'est qu'on peut faire beaucoup plus que mes mini problèmes d'exemple. Parmi les fichiers cnf mis à dispositions ici on en trouve un qui compte 1040 variables et 3668 clauses que Minisat résoud (comme "UNSATISFIABLE") en...0m0.013s ! Dans la même catégorie on trouve un autre fichier de test contenant 1501 variables et 3575 clauses que Minisat résoud (en "SATISFIABLE" avec une solution exemple) en 0m0.008s.

Avec une telle puissance de résolution que peut-on faire ? On peut, par exemple, attaquer des algorithmes de hachage faibles, comme l'indique l'un des deux articles déclencheur de ce billet. On peut également aller beaucoup plus loin et se mettre à taquiner la recherche de vulnérabilité ou la génération de code d'exploitation comme le montre le second lien initiateur de ce billet. De plus, j'ai en mémoire d'avoir vu quelque part des outils de fuzzing qui utilisaient des SAT solver pour augmenter leur couverture de test, mais je ne parviens plus à retrouver de liens pertinents :( ...Enfin, pour ma part, je vais probablement tenter d'insérer une intervention de SAT solver dans mon analyseur de code PHP afin de décider plus précisément si un bout de code est accessible ou pas; ou encore tenter de transcrire au formalisme SAT le prochain problème que je rencontrerai et pour lequel je n'aurai pas de meilleure idée qu'un brute-forceur :)

Et vous, qu'en ferez-vous ;) ?


Gorgonite le 2012/08/11 22:37

perso, je verrais plus Model-Checking + SAT pour prouver des propriétés de sécurité (plus du côté safety en ce qui me concerne, mais tout dépend de ce que tu veux prouver).

Sinon as-tu regardé du côté de SMT (SAT Modulo Theories) ?
http://fr.wikipedia.org/wiki/Satisf...

A priori, les propriétés sont quand même plus haut-niveau et il est probable que tu n'aies pas encore des problèmes à 10^9 états...

Ozwald le 2012/08/12 21:32

Je dois avouer que j'attendais un commentaire de ta part sur ce sujet ;-) !

J'avais aussi jeté un oeil au niveau des SMT (le gars qui se sert d'un solveur SAT pour casser du hachage faible utilise un SMT dans la seconde partie de son article), c'est également sympa mais j'ai l'impression qu'il est plus délicat d'en trouver qui fonctionnent "out of the box". Ceci dit si tu as un solveur SMT préféré à me conseiller (et qui s'installe sans devoir recompiler 50 librairies exotiques à la main) je suis preneur de l'information :-)

Gorgonite le 2012/08/15 00:06

Pas tellement de conseils... c'est pile à côté de mon sujet de thèse (une extension envisagée)
Regardes du côté de opensmt par exemple :)

Gorgonite le 2013/10/16 06:16

SAT + Model-Checking, j'ai parcouru un bouquin aujourd'hui... j'ai repensé à ton poste :)
http://alloy.mit.edu/alloy/

  1. Merci Wikipédia
  2. En tout cas beaucoup plus efficace qu'un être humain devant réaliser la même tâche
  3. Minisat est masqué sous gentoo par ~x86, mais il est tout de même packagé
  4. Vous devinerez que j'ai affecté 1 à la variable A, et 2 à la variable B
  5. On remarque au passage que Minisat nous propose la solution A=Faux, B=Vrai alors qu'en exemple moi j'avais donné A=Vrai, B=Vrai. Les deux solutions sont valides pour ce problème.

Brèves du jour

Par Oz le - Geek
I.A. Outil Réseau python scripts

Un mini billet pour deux petites brèves : une astuce python (déjà bien connue, mais plus on réplique ce genre d'info moins on a de mal à la retrouver quand on l'a oublié), et un pointeur sur un jouet sympa.

Tools - Creative Common by mtneer_man on Flickr

Tout d'abord l'astuce python : comment changer son user-agent quand on utilise la librairie urllib. C'est un problème ultra-classique puisque pas mal de sites font du filtrage sur ce user-agent et refusent de répondre quand ils repèrent un script python1. En fouillant sur le net on trouve pleins de méthodes plus ou moins bidons (certaines se contentent carrément de rajouter un second header "user-agent", ce qui n'est évidemment pas ce que l'on cherche à faire), et après en avoir testé au moins une demi-douzaine voici celle que j'utilise à présent (et qui marche :D) :

import urllib
# ============ USER AGENT MAGIC ===========
class UAOpener(urllib.FancyURLopener):
        version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11'
urllib._urlopener = UAOpener()
# =========================================

Et voilà :) Comme pour le passage via TOR c'est tout ce qu'il y a à faire. Accessoirement j'ai réalisé récemment que le dernier paramètre de "setdefaultproxy" que j'utilise pour passer par TOR souffre un bug ennuyeux : il est ignoré :-D Donc que vous mettiez à "True" ou à "False" les résolutions DNS ne passeront JAMAIS par votre proxy socks (et donc par TOR)...ennuyeux n'est-ce-pas ? En tout cas maintenant vous êtes prévenus :)

Le petit jouet maintenant : ça n'a rien de nouveau non plus, mais c'est tout de même un jouet rigolo. Il s'agit du WOrdnet Libre du Français2. Pour ceux qui connaissent Wordnet : c'est Wordnet pour le Français ;) Pour ceux qui ignorent ce qu'est Wordnet c'est une base de donnée concernant le sens des mots et leurs relations les uns avec les autres. Un usage immédiat de Wordnet c'est de trouver des synonymes (dans la langue française avec WOLF, dans la langue anglaise avec le Wordnet original), un autre usage consiste à mesurer la proximité de sens entre deux mots par exemple. Les possibilités sont vraiment nombreuses, notamment en data-mining. Bref vous pouvez le télécharger ici au format XML, et ces trois mini remarques pourraient vous êtes utiles si vous voulez travailler avec :

  • Le document ne contient pas de balise racine, ajoutez donc en une si vous voulez que xmllint --format ou xml.dom.minidom.Parse ne vous insulte pas. Par exemple un petit <wolf> en début de document et un petit </wolf> en fin de document feront parfaitement l'affaire.
  • Les & ont tendance à faire crier le module python xml.dom.minidom. Pour ma part je les ai donc purement et simplement supprimés grâce à un petit sed.
  • Le XML pèse 38Mo sur disque, une fois parsé par xml.dom.minidom mon interpréteur Python prend plus de 1Go ;-) Veillez donc à avoir de la RAM disponible.

Gorgonite le 2011/10/22 13:45

MiniDOM... tu cherches aussi les ennuis pour traiter une telle quantité de données :p

  1. Par exemple wikipedia.
  2. WOLF