未名網記

Aller au contenu | Aller au menu | Aller à la recherche

vendredi 5 décembre 2008

re: bloup

Bon je suis pas sûr que mon interprétation soit la bonne mais le "bloup" de Romain à l'air de signifier que je poste pas beaucoup de messages. Ce qui n'est pas complètement faux. (bon ok, mon interprétation est aussi arbitraire que son signe)

Petit message donc pour les parisiens qui vivent par 2⁰C. Encore mercredi, on a frôlé les 27 ! heureusement le matin il faisait un peu plus frais et en arrivant à la fac un peu avant 9h (par 23⁰C) j'ai pu prendre mon petit dej dehors, au bord du lac (le "lac de l'ivresse (sous la) lune", 月醉湖). Rassurez-vous, une douce brise rendait la chaleur supportable. Ça se passait donc en compagnie des tortues (timides les tortues), des cygnes (qui dormaient encore les bougres), des canards faisant la ronde et des cigognes veillant majestueusement sur tout ce petit monde (ou était-ce des grues ? ou peut être des héron ? quel piètre zoologue je fais).

(Et dire qu'on est en décembre. Après mon doctorat ici, je veux un post-doc à la Réunion !),

Ah mais j'ai jamais parlé de ma fac ici. En fait je vis un peu à l'écart de la ville, juste devant l'académie où est mon labo. Mais je suis des cours dans une université dont le campus est en centre-ville. Un car fait la navette entre les deux plusieurs fois par jour. Ce qui est bien pratique puisqu'il met 20mn là ou le métro en prend 40. Le hic c'est qu'il passe pas souvent donc quand j'ai cours à 9h30, j'arrive à la fac vers 8h50 et je mange sur place. Ce qui n'est pas pour me déplaire...

petite vidéo du lac

cygogne

si si, c'est bien à l'intérieur de la fac !

cygne

tortuess la quête des tortues timides est laissée en exercice au lecteur (cliquer sur les photos pour agrandir)

samedi 20 septembre 2008

为学日益,為道日損

Quelques images du quotidien, suivez moi !

Bienvenue à la résidence ! entrée

Sortie de ma chambre, vue sur la cour intérieure (version sans typhon) : cour de la résidence

Sur le chemin de l'école... enfin, de l'académie... : chemin de l'école

L'entrée de l'académie : A.S.

La vue du bureau des doctorants, ça le fait : 603-1

Et ce qui est chouette, c'est que tout la façade est vitrée : 603-2

Autre angle (L'académie s'agrandit dans cette direction) : 603-3

Et en cas d'incendie, on s'éclate : 603-4 (on est au 6ème)

Enfin le soir, direction le théatre national, mes entrainements de bagua zhang (八卦掌) ont lieux sur la place devant ce bel édifice : théatre

samedi 13 septembre 2008

OCamlyacc, Ulex et Sinica Treebank

Ce qu'il y a de bien avec les typhons, c'est que tout s'arrête autour, du coup on est peinard pour bosser et faire ce qu'on avait mis de côté depuis des mois...

Et ça fait des mois que j'avais envie de tester Ocamlyacc sans trop avoir de raison ni de temps pour ça. Ce week end, j'avais le temps ! Et la raison : m'attaquer au Sinica Treebank. Bon, Yacc pour parser un treebank c'est p'tet un peu disproportionné mais c'était l'occasion et puis quand on voit le résultat, on se dit qu'on a bien fait puisqu'on arrive à ce qu'on veut en moins de 100 lignes de code !. Demonstration...

(en fait je suis pas sûr que ce billet soit lisible, disons qu'il y a quelques pré-requis. Si il ne l'est pas, considérez que c'est plus un aide mémoire perso et/ou posez des questions en commentaire)

Le Sinica Treebank (STB)

http://turing.iis.sinica.edu.tw/treesearch/

Le STB est comme je l'ai dit dans le premier billet un treebank construit suivant une "Information-based Case Grammar". J'avoue n'avoir que survolé le papier qui décrit ce qu'est vraiment une ICB. Mais pour l'heure ce que j'en retiens et qui est suffisant pour mon propos ici, c'est que c'est une grammaire d'unification, "Head-Driven", et que les rôles thématiques des adjoints aux têtes sont clairement indiqués dans le Treebank. concrêtement, ça donne ça :

S(restriction:Cbbb:不僅
|experiencer:NP(
    Head:Nab:遊客)
|Head:VL1:喜愛
|goal:VP(
    Head:VA11:來
    |location:Nep:此
    |complement:VP(
        Head:VB11:拍照
        |complement:VI2:留念)))

en français mot à mot :

S(restriction:Cbbb:pas seulement
|experiencer:NP(
    Head:Nab:touristes)
| Head:VL1:aimer
|goal:VP(
    Head:VA11:venir
    |location:Nep:ici
    |complement:VP(
        Head:VB11:prendre photo
        |complement:VI2:garder un souvenir)))  

L'indentation est maison, en vrai ça donne ça :

S(restriction:Cbbb:不僅|experiencer:NP(Head:Nab:遊客)|Head:VL1:喜愛|goal:VP(Head:VA11:來|location:Nep:此|complement:VP(Head:VB11:拍照|complement:VI2:留念)))

L'objectif est donc de passer d'une chaîne de caractères à une structure de donnée en arbre. Qui permettra notamment de générer ce genre de chose, beaucoup plus lisibles :

demo STB

Formats des données

En observant les données si dessus, on peut dégager la grammaire suivante : (oui la grammaire du format du Treebank hein, rien à voir avec la grammaire du chinois

noeud -> rôle ':' pos ':' mot
    | rôle ':' pos '(' liste_noeuds ')'
    | pos '(' liste_noeuds ')'

liste_noeud -> noeud
    | noeud '|' liste_noeud

"rôle", "pos" et "mot" sont des chaînes de caractères quelconques. Tellement quelconques que ça inclus des sinogrammes. Pour éviter tout risque de cafouillage dans les encodages et me faire la main au passage, j'ai donc choisi d'utiliser de l'UTF-8. Ce qui disqualifie Ocamllex pour le lexeur. En fouillant un peu, on trouve Ulex. Un lexer "unicode aware" qu'on peut facilement conjuger à ocamlyacc.

Il faut aussi définir une structure de données qui recevra les informations pendant le parsing. Au passage, on prévoit quelques fonctions d'affichage. Voici :

stb.ml


type case = Case of string
type pos = POS of string
type node = Node of case*pos*string* node list

let print_node_string n = 
        let rec aux_liste l = match l with
                [] ->()
                |f::suite -> aux f; aux_liste suite
        and aux f = match f with
                Node(_,_,s,fils) -> print_string s ; aux_liste fils
        in aux n
         
let rec indent n = if n>0 then (print_string "    " ; indent (n-1)) else ();;

let print_node_tree n =
        let i = ref 0 in
        let rec aux_liste l = match l with
                [] ->()
                |f::suite -> aux f; aux_liste suite
        and aux f = match f with
        Node(Case(c),POS(p),"",fils) -> indent !i ; print_endline (c^":"^p) ; i:= !i+1; aux_liste fils; i:= !i-1
                |Node(Case(c),POS(p),s,[]) -> indent !i ; print_endline (c^":"^p^":"^s)  
                | _ -> print_string "error"
        in aux n

let print_node_dot racine =
        let n = ref 1 in
        let rec aux_liste feuilles pere_id l = match l with
                [] -> feuilles
                |f::suite -> let feuilles'= aux feuilles pere_id f in  aux_liste feuilles' pere_id suite
        and aux feuilles pere_id f = match f with
                Node(Case(c),POS(p),"",fils) -> 
                        n := !n+1; 
                        let id = "n"^(string_of_int !n) in 
                        print_endline (id^" [label="^p^"];");
                        print_endline (pere_id^" -> "^id^" [label="^c^"];");
                        aux_liste feuilles id fils 
                |Node(Case(c),POS(p),s,[]) -> 
                                n:= !n+2; 
                                let id ="n"^(string_of_int (!n-1)) in 
                                let id2 = "n"^(string_of_int !n) in
                                print_endline (id^" [label="^p^"];");
                                print_endline (id2^" [label="^s^"];");
                                print_endline (pere_id^" -> "^id^" [label="^c^"];");
                                print_endline (id^" -> "^id2^";");
                                id2::feuilles
                | _ -> print_string "error";[]
        in match racine with
                Node(_,POS(p),_,fils)-> 
                        print_endline "digraph g {";
                        print_endline ("n1 [label="^p^"];");
                        let feuilles = aux_liste [] "n1" fils in
                        print_endline ("{rank=same"^(List.fold_left (fun a b -> a^";"^b) "" feuilles)^"}")
                ; print_endline "}"

Lexing

Contrairement à Lex&Yacc et avec eux Ocamllex et Ocamlyacc, Ulex n'a pas été codé comme un générateur de code à recompiler, mais directement comme une extension de la syntaxe d'Ocaml grâce à camlp4. Il faudra donc utiliser ce dernier pour compiler directement le lexeur.

La syntaxe de Ulex reste très proche de celle de lex et ocamlex et ne pose pas de problème en elle même. Voici le code utilisé

lexer.ml

type lexeme = SepAttributs |SepNodes | ParOuvre  | ParFerme | Mot of string
 

(*open Parser*)

let mon_lexer = lexer ':' -> SepAttributs
        | '|' -> SepNodes
        |'(' -> ParOuvre
        |')' -> ParFerme
        | [^ ':' '(' ')' '|' ]+ ->Mot( Ulexing.utf8_lexeme lexbuf)

pour le compiler, le plus simple est d'utiliser ocamlfind :

ocamlfind ocamlc -package ulex -linkpkg -syntax camlp4o lexer.ml

Parsing

Côté parsing pas de surprise ; à ce niveau on ne dépend plus de l'encodage des données.

Ocamlyacc fonctionne de la même façon que Yacc : on écrit notre grammaire dans un fichier .mly et on lance ocamlyacc fichier.mly pour obtenir un .ml qu'on peut compiler normalement pour obtenir un parser. Dans les fait pour que ça marche, j'ai du retouché légèrement le fichier d'interface parser.mli pour y ajouter open Stb afin qu'il trouve des déclarations de types manquantes.

le format du fichier .mly est très proche de ce qu'on trouve en Yacc. Voici le mien :

parser.mly

%{ 
open Stb
%}

%token SepAttributs SepNodes ParOuvre ParFerme
%token <string> Mot

%start noeud
%type <node> noeud

%%

noeud : Mot SepAttributs Mot SepAttributs Mot{Node(Case($1), POS($3), $5, [] )  }
        | Mot SepAttributs Mot ParOuvre liste_nodes ParFerme
        {Node(Case($1),POS($3),"",$5) }
        | Mot ParOuvre liste_nodes ParFerme{Node(Case(""),POS($1),"",$3) }

liste_nodes : noeud {[$1]}
                | noeud SepNodes liste_nodes{ $1::$3}

%%

Assemblage des morceaux.

Maintenant, l'astuce consiste à brancher notre lexeur Ulex à la place d'un lexeur classique généré avec OCamlex. Pour appeler le parseur il faudra donc faire quelque chose comme :

let resultat = parse (fun _ -> mon_lexeur lexbuf) (Lexing.from_string "non_utilisé")

Ce qui nous donnera... Une erreur de type !!! (bah oui, on est en caml. Passez une journée sur du code caml sans obtenir d'erreur de typage, c'est pas crédible. Fallait bien que j'en laisse au moins une.)

This expression has type Lexer.lexeme but is here used with type Parser.token

Et oui, il faut quand même que le lexeur et le parseur s'entendent sur les données manipulées... corrigeons lexer.ml en remplaçant la déclaration du type lexeme par un simple open Parser et le tour est joué !

Démo

Voici donc ce que ça donne :


[pierre@Arch ocamlParse]$ ocaml -I /usr/lib/ocaml/site-lib/ulex/ ulexing.cma parser.cmo lexer.cmo stb.cmo 
        Objective Caml version 3.10.1

# open Parser;;
# open Lexer;;
# let lb = Ulexing.from_utf8_string "S(restriction:Cbbb:不僅|experiencer:NP(Head:Nab:遊客)|Head:VL1:喜愛|goal:VP (Head:VA11:來|location:Nep:此|complement:VP(Head:VB11:拍照|complement:VI2:留念)))";;
val lb : Ulexing.lexbuf = <abstr>
# let resultat = noeud (fun _ -> mon_lexer lb) (Lexing.from_string "bidon");;
val resultat : Stb.node =
  Stb.Node (Stb.Case "", Stb.POS "S", "",
   [Stb.Node (Stb.Case "restriction", Stb.POS "Cbbb",
     "\228\184\141\229\131\133", []);
    Stb.Node (Stb.Case "experiencer", Stb.POS "NP", "",
     [Stb.Node (Stb.Case "Head", Stb.POS "Nab", "\233\129\138\229\174\162",
       [])]);
    Stb.Node (Stb.Case "Head", Stb.POS "VL1", "\229\150\156\230\132\155", []);
    Stb.Node (Stb.Case "goal", Stb.POS "VP ", "",
     [Stb.Node (Stb.Case "Head", Stb.POS "VA11", "\228\190\134", []);
      Stb.Node (Stb.Case "location", Stb.POS "Nep", "\230\173\164", []);
      Stb.Node (Stb.Case "complement", Stb.POS "VP", "",
       [Stb.Node (Stb.Case "Head", Stb.POS "VB11",
         "\230\139\141\231\133\167", []);
        Stb.Node (Stb.Case "complement", Stb.POS "VI2",
         "\231\149\153\229\191\181", [])])])])
# Stb.print_node_string resultat;;
不僅遊客喜愛來此拍照留念- : unit = ()
# Stb.print_node_dot resultat;;
digraph g {
n1 [label=S];
n2 [label=Cbbb];
n3 [label=不僅];
n1 -> n2 [label=restriction];
n2 -> n3;
n4 [label=NP];
n1 -> n4 [label=experiencer];
n5 [label=Nab];
n6 [label=遊客];
n4 -> n5 [label=Head];
n5 -> n6;
n7 [label=VL1];
n8 [label=喜愛];
n1 -> n7 [label=Head];
n7 -> n8;
n9 [label=VP ];
n1 -> n9 [label=goal];
n10 [label=VA11];
n11 [label=來];
n9 -> n10 [label=Head];
n10 -> n11;
n12 [label=Nep];
n13 [label=此];
n9 -> n12 [label=location];
n12 -> n13;
n14 [label=VP];
n9 -> n14 [label=complement];
n15 [label=VB11];
n16 [label=拍照];
n14 -> n15 [label=Head];
n15 -> n16;
n17 [label=VI2];
n18 [label=留念];
n14 -> n17 [label=complement];
n17 -> n18;
{rank=same;n18;n16;n13;n11;n8;n6;n3}
}
- : unit = ()
# 

Dès que le vent soufflera !

Bon, dans les faits je suis parti avant que ça ne souffle, et c'est l'avion qui m'a pris pas la mer.

Mais une chose est sure, le vent se rattrape bien, qu'est ce que ça souffle ici ! Et oui, en ce moment, je goûte à mon premier typhon ! Son petit nom c'est Sinlaku. Il est relativement lent, 15km/h (Il est resté longtemps au large à se faire attendre) mais provoque des vents qui vont jusqu'à 50m/s. Bon il n'est pas vraiment sur nous, mais ça souffle à 25m/s dans les 100km à la ronde. Il fait un petit crochet par le nord de l'île et devrait ensuite se diriger vers le Japon.

Mardi dernier j'ai raté mon premier tremblement de terre. il y en a eu un relativement gros parait-il, mais je n'ai rien senti ! Alors je profite du typhon.

Vous l'aurez compris : regarder la météo ici, c'est autrement plus palpitant qu'en France (où j'ai toujours eu du mal à comprendre l'intérêt du rituel de 20h40). D'ailleurs il y a site gouvernemental dédié aux alertes de typhons et tremblements de terre. On y trouve de jolies images comme celles-ci :

Sinlaku : route

Qui montre la route observée et prévue, ou celle-ci :

Sinlaku : proba

Qui donne une estimation des chances qu'on a de s'en prendre plein la gueule ! Sympa, moi je suis dans la zone rouge, à plus de 80%, et je confirme.

Le pire est encore à venir, pour demain en début d'après-midi si j'ai bien compris. Mais c'est déjà assez fun.

Déjà, il faut savoir que c'est normal ici, et je dois être le seul que ça amuse. Un typhon ne frappe pas par surprise, on le voit arriver. L'histoire récente a montré qu'on ne fait pas toujours ce qu'il faut dans ces cas là mais à Taïwan, on se prépare. Ici il y a peu de jours fériés pour raison religieuse ou traditionnelle comparé à la France, mais quand un typhon sérieux arrive le gouvernement déclare que c'est un jour "off". Restez chez vous citoyen, il n'y aura rien à voir ni à faire. D'ailleurs c'est pas dit que vous pourrez mettre le nez dehors. Résultat les gens vont acheter des vivres pour se réfugier chez eux.

À Rome comme les romains, nous fîmes de même (avec les félicitations du gardien de la résidence ("yeah ! You're right, the Typhoon is coming !"). Ce week-end ce sera viande séchée et nouilles instantanées au menu (bon, j'ai aussi fait un stock de 饅頭, des sortes de petites brioches fort adaptées à l'occidental en mal de petit-dej' ou pour les petits creux laissés par les nouilles et quelques fruits). Mais bon, pour l'instant on a encore électricité, eau courante et internet... (tiens, sans eau chaude, j'aurais l'air con avec mes nouilles)

Voici un petit aperçu de ce que ça donne vu de ma fenêtre (photos cliquables). Cet après-midi :

typhon 1

de l'autre côté, vue de ma porte :

typhon 2

et de nuit : (photo lourdement retouchée pour qu'on y voit quelque chose, j'avais pas trop envie d'ouvrir la fenêtre)

typhon 3

Petit détail qui a son importance, ma porte donne sur une sorte de balcon qui mène à l'ascenseur en rerentrant dans le bâtiment. Première effet kisskool : je dois donc aller dehors pour atteindre la cuisine. Deuxième effet kisskool : ma chambre prend l'eau et je dois régulièrement essorer la serpillère que j'ai mise au pied ma porte !

Entre l'eau et le bruit du vent, je me rend compte que la voile me manque ! Mais je te rassure maman, naviguer par 7/8 Beaufort, ça me dit pas trop.

Je m'arrête là pour l'instant, je ferai surement une mise à jour demain quand Sinlaku aura montré sa pleine puissance...

lundi 8 septembre 2008

ROCLING 2008

Ouvrons ce blog sur quelque chose de sérieux, je reviendrais sur mon arrivée à Taïwan et me premières impressions une autre fois.

rocling

Jeudi et vendredi derniers se son déroulées les conférences ROCLING 2008 dans les locaux de l'université normale nationale de taïwan (NTNU, pour les intimes et pour ceux qui aiment les cigles). Rien de tel donc pour ouvrir ce blog et fêter ma première semaine ici !

ROCLING, qu'est ce que c'est ? En chinois dans le texte ça donne 自然語言與語音處理研討會, "conférences sur le traitement automatique des langues et de la parole. Organisé par l'ACLCLP (Association for Computational Linguistics and Chinese Language Processing,中華民國計算語言學學會), c'est un peu la version taïwanaise de TALN (et l'ACLCLP, c'est l'ATALA). Ne vous en faites pas, j'arrête avec les cigles !

J'avais été prévenu de cette conférence il y a à peu près un mois. À la vue du programme, je m'attendais à une alternance de conf en chinois et en anglais ; il n'en fut rien ! Tout était en chinois, tout ? Oui, ou presque : j'ai eu droit à un splendide "speech" d'ouverture dans un chinglish parfait comme je n'en avais jamais entendu. Pour faire un bon chinglish c'est très simple : prenez des phrases bien formées en chinois et traduisez tous les mots pleins en anglais, les termes techniques bien sur, mais tant que vous y êtes, les autres aussi ! Traduisez-en le plus possible et ne conservez du chinois que sa structure et quelques mots de liaisons (quoi que ça fait toujours bien d'en placer aussi quelques uns en anglais, un "anyway..." par ci, un petit "also" par là et vous aurez l'air... Euh vous aurez l'air quoi au juste ?!? J'en sais trop rien. à priori je trouve ça plutôt moche, mais je dois avouer que c'est le "talk" que j'ai le mieux compris ! Et puis en y repensant, ça doit être naturel pour un chercheur chez Microsoft Research Asia.

Les autres interventions étaient faites dans des chinois plus "purs", ce que j'en ai compris est très variable, mais en gros quand le support de conf' projeté était en anglais, j'arrivais à peu près à m'accrocher et je pouvais suivre le discours, c'était encore mieux quand au moins l'abstract du papier correspondant était en anglais et que je connaissais un peu le thème et le domaine de la conférence. À l'opposé, les conf de traitement du signal en pur chinois, euuuuh, comment dire ? C'est totalement hors de portée ! Dommage puisque l'un d'eux présentait une méthode utilisant des ondelettes pour dissocier le son de la parole d'une musique de fond, j'aurais aimé y comprendre quelque chose pour le raconter à Florent (le spécialiste et préposé aux ondelettes dans la famille). Mais finalement, j'en ai plutôt profité pour faire une sieste digestive, car la nuit précédente fut courte, la matinée avait été rude et le repas fort bon.

La première conférence était donc la plus compréhensible, mais pas la plus intéressante pour moi. il y était question de moteur de Question-Réponse basé sur l'indexation et la classification des sites genre Yahoo! Answers ou Baidu 知道, son équivalent chinois. Une petite pensée pour Nico donc. (le powerpoint est en ligne sur site de Rocling, ainsi que tous les actes je crois. Moi j'ai eu droit à jolie clef USB avec tous les pdfs et ppt, en plus du bottin avec les actes, cf la photo plus haut).

La première session était celle qui m'intéressait le plus ; centrée sur la sémantique lexicale. Avec notamment une intervention de Chen Keh-Jiann (陳克健) qui est mon "research advisor" provisoire pour cette année. Il nous parlait de composition sémantique dans le Sinica Treebank, thème qui m'amuse beaucoup. Ici point de lambda calcul mais de l'unification, dommage car c'est marrant le lambda calcul... Son papier me donne l'occasion de me familiariser avec le Treebank qui est plus plat que je ne l'imaginais, il suit une "Information based Case Grammar" (ICG). À creuser !

Une autre intervention intéressante était celle de Huang Chu-ren (黃居仁) sur la segmentation. Il présentait des résultats que j'attendais avec impatience correspondants à un systèmes dont les grandes lignes avaient été présentées dans un papier de 2007 co-signé avec Laurent Prévot, un français en post-doc à l'Académia Sinica l'année dernière. Ce système présente l'originalité de s'intéresser plus à l'espace entre les sinogrammes qu'aux chaînes de caractères possibles. Et ses performances montrent qu'il est totu à fait pertinent. J'y reviendrait sûrement aussi

Une petite pensée pour Yoann aussi lors de la présentation d'un système de saisie en taïwanais, l'inexistence d'un tel système et les conséquences que ça peut avoir sur les locuteurs était un de nos grand sujet de conversations ces derniers mois ! Dans la série traitement automatique du taïwanais, on a vu aussi un étiqueteur de taïwanais romanisé entrainé sur des ressources en chinois avec conversion des transcriptions latines en sinogramme avant étiquetage puis retour au latin. La raison d'une telle quadricapillosectomie est bien sûr l'absence de ressources linguistiques type corpus étiqueté en taïwanais. Ce système a une précision de 91% ce qui n'est pas vraiment terrible. Les sources d'erreurs sont discutées dans le papier mais j'avoue avoir un peu décroché sur cette partie de la présentation !

Je dois dire que cette méthode tordue est assez caractéristique d'une tendance dans le TAL qui me laisse un peu perplexe mais contre laquelle je n'ose pas vraiment me lever : celle de "faire ce qu'on peut avec ce qu'on a". Assez souvent les techniques utilisées sont plus influencées par les ressources disponibles que par une théorie linguistique solide, je trouve ça dommage. D'un autre côté, commencer par établir une théorie solide aboutirait dans bien des cas à une impasse due à l'absence de la ressource adéquate... dur dur.

Voilà donc, deux jours de conférences forts sympathiques, mais excessivement crevant ! Pendant lesquels on était bien nourri donc tout à fait disposés à l'étude (et à la sieste à certains moments, mais c'est une tradition ici). Deux jours qui m'auront permis d'être tout de suite dans l'ambiance !

lundi 7 avril 2008

Is There Anybody Out There ?

plop