Správce experimentů TEM
Následují mé pracovní poznámky o chystaném nástroji pro správu experimentů s pracovním názvem TEM (Treex Experiment Manager), tedy co bych od něho čekal.
- to, co teď dělá en2cs/Makefile, případně něco z vylepšených verzí Ondry Duška (které logují víc věcí).
- příkaz tem by byl v PATH, takže bych nemusel pořád kopírovat Makefiles a skript compare_stats.pl
- Mé názvosloví a základní principy:
“Experiment” obsahuje “runy”.
Runy jsou podadresáře experimentu (asi ještě v podadresáři runs). Název runu začíná pořadovým číslem, které ho plně identifikuje, pak je v názvu adresáře i datum případně typ runu. Jednotlivé runy (stejného typu, viz dále) jednoho experimentu jsou porovnatelné, tedy mají stejná zdrojová data (překládaný/analyzovaný text). Chci-li jiná zdrojová data, musím si na to založit nový adresář (nový experiment). Každý experiment má svou “konfiguraci” v texťáku. Je samozřejmě možné mít třeba scénáře sdílené pro více experimentů. Takže když si vlezu do adresáře en-cs/Batch2a, tak už nemusím zadávat na příkazovou řádku parametry en-cs a Batch2a, je to v konfiguráku. Ještě zvažuji, zda umožnit spustit run jen na podmnožině zdrojových dat (např. jen prvních 10 vět na otestování), nebo jestli na to bude třeba založit si podadresář s novým experimentem, který by zdědil většinu konfiguráku z “rodičovského” experimentu.
- snadné tagování runů
V en2cs je jediný tag “baseline” a pak implicitně poslední run. Já bych rád příkaz “tag”, kterým si otaguji libovolný run a mohu pak místo jeho čísla používat tag:
tem tag 001 baseline tem tag 002 skyline tem tag 123 Pilot0
Váhám, zda využít syntaxi ~N z gitu, takže třeba baseline~2 by byl run s číslem o 2 menším než run s tagem baseline. Příkaz “tem lastdiff” by pak byl zkratkou za “tem diff LAST LAST~1”. (Něco jako lastdiff chci mít každopádně, to mi teď dost chybí.) Tag musí být unikátní v daném experimentu (možná bych tomu tedy neměl říkat tag, ale třeba name či alias, ale to teď neřeším). Mohu zadat tag rovnou, když experiment spouštím (tem run D=“longer description” tag=MaxEnt).
- snadné mazání nepotřebných experimentů
Například smazat všechny neotagované runy jedním příkazem. Nebo v nich jen smazat treexfiles a nechat metadata.
- vyhodnocení
Každý run může mít několik číselných výsledků (BLEU, NIST,…), TEM je pak umí vypsat v tabulce apod. Taky bych předpokládal nějaký textový výstup každého runu (u některých experimentů může chybět). Pro překlad, t-roundtrip a mnoho dalších NLP úloh má smysl definovat referenční/gold výstup a porovnávat dva runy spolu vzhledem k té referenci, jako to dělá současný “make compare”. Toto by měl umět i TEM.
- rozšíření
Základní TEM by uměl spouštět treexové scénáře na daná data. Tedy “tem run” by spustilo hlavní scénář a vytvořilo nový run. Zvažuji, zda (a hlavně jak) by se mohlo v konfiguráku specifikovat další “akce” (viz typy runů dále). Tedy např. různé druhy evaluací (které ale nechci provádět automaticky v každém runu v rámci hlavního scénáře)
- volitelně logovat k runům i necommitnuté změny v svn (či gitu, až na něj přejdeme)
Takto to má Luis, že ukládá výsledek “svn diff” zavolaný v nějakém “hlavním” adresáři. Chtělo by to ale volat v jiném vlákně, aby to nezpomalovalo spuštění vlastního runu.
- závislosti runů
Častá situace:
1. krok zanalyzovat zdrojový text (třeba na t-rovinu)
2. krok extrakce featur
3. krok natrénování modelu (mimo Treex) a jeho případná intrinsická evaluace
4. krok zanalyzovat testovací data
5. krok použít na data z kroku 4 model z kroku 3
6. krok vyhodnotit krok 5
Tohle potřebujeme v QTLeapu, s Ondrou Duškem na valenční rámce a leckde jinde. Ondra na to má (makefilový) systém, kde se každý krok spouští v jednom runu (v mém názvosloví). Takže mám vedle sebe adresáře runů 010-analyze-train-data, 011-extract-from-010, 012-train-from-011, 013-train-from-011. Samozřejmě můžu mít i víc runů od jednoho typu kroku (např. 012 a 013 v příkladu výše). Jinými slovy: jednotlivé runy na sobě závisejí. Při spouštění kroku 2 musím zadat číslo runu z kroku 1, který se má použít, atd.
Kdybych chtěl mít všechny runy v jednom experimentu porovnatelné (tedy nutně stejného typu), tak bych pro každý krok (typ runu) musel zakládat jiný experiment, ale to by vše asi spíš zkomplikovalo než zjednodušilo. Každý run tedy bude mít přiřazen typ.
Toto se nebezpečně podobá Emanovi, který je na závislostech runů (kterým říká steps) založen. Pořád si ale myslím, že v Treexu je častější situace, že změním kód nějakého bloku, případně scénář a chci vyhodnotit nový run. V en2cs mám vlastně jen jeden krok (tedy dva: překlad a evaluaci, ale dělám je vždy dohromady). Na to se myslím Eman moc nehodí. TEM by měl být jednodušší než Eman, ale měl by mít nějakou základní podporu pro typy runů a jejich závislosti.
Mimochodem: v Ondrových makefiles i v Emanovi mi dost chybí jedna věc. Nejde si jednoduše napsat skript (a poslat to někomu jako návod), který provede několik kroků, které na sobě závisí. Nevím totiž, jak se přesně bude nový run jmenovat (pokud začínám v čistém adresáři, tak u Ondrových makefiles jdou čísla runů po sobě, takže by to šlo, ale není to moc spolehlivé). V TEMu mohu zadat unikátní tag při spouštění nového runu. A tento tag pak mohu použít pro specifikaci závislosti:
tem analyze DATA=pcedt-train tag=AnalyzeTrain tem analyze DATA=pcedt-dtest tag=AnalyzeDTest tem extract from=AnalyzeTrain tag=ExtractTrain tem extract from=AnalyzeDTest tag=ExtractDTest tem train train=ExtractTrain dtest=ExtractDTest classifier=VW tag=TrainVW ...
- automatické hledání parametrů
Toto bych do TEMu nepletl. Existuje na to mnoho nástrojů (Spearmint, SMAC, hyperopt,…), které toho umí mnohem víc než grid-search, random-search, annealing,… Ideálně by mělo být možné tyto nástroje nakonfigurovat tak, aby vytvářely runy v TEMu (tedy každé vyhodnocení optimalizované fce spustí “tem run eval params=$PARAMS”) a šlo si potom nechat v TEMu vypsat výsledky do tabulky. Až to někdo prozkoumá, tak bychom to měli sepsat jako best practice do dokumentace TEMu.
- Treex::Core::Dataset,
aby šlo mít instanci objektu $pdt a $pennTB jako v NLTK. Toto s TEMem souvisí jen zcela okrajově. Třeba pro extrakci featur by se hodilo mít něco jako my $pdt = Treex::Dataset::PDT3→new(server⇒'cosmos:1234'), ale byla by to nějaká další rovina, která by souvisela s paralelizací Treexu a možností mít data někde permanentně v paměti. (Nezávisle na tom se můžeme snažit zmenšit paměťovou reprezentaci, aby se PDT vešlo do paměti na jednom stroji.) Souvislost s TEMem je, že výsledky některých runů (analyze) by také mohlo být výhodné mít načtené permanentně v paměti a reprezentované v Treexu jako objekt typu Dataset.