From 2908bf2b735f4104c445e3679ce46746fd496984 Mon Sep 17 00:00:00 2001 From: lvapeab Date: Thu, 20 Apr 2017 13:03:13 +0200 Subject: [PATCH 01/25] More info when compiling + Keras metrics --- model_zoo.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/model_zoo.py b/model_zoo.py index 0a26cf6..8783a31 100644 --- a/model_zoo.py +++ b/model_zoo.py @@ -33,6 +33,9 @@ def __init__(self, params, model_type='Translation_Model', verbose=1, structure_ (if None, then it will be assigned to current time as its name) :param vocabularies: vocabularies used for word embedding :param store_path: path to the folder where the temporal model packups will be stored + :param set_optimizer: Compile optimizer or not. + :param clear_dirs: Clean model directories or not. + """ super(self.__class__, self).__init__(type=model_type, model_name=model_name, silence=verbose == 0, models_path=store_path, inheritance=True) @@ -123,8 +126,9 @@ def setOptimizer(self, **kwargs): """ # compile differently depending if our model is 'Sequential' or 'Graph' if self.verbose > 0: - logging.info("Preparing optimizer: %s [LR: %s] and compiling." % - (str(self.params['OPTIMIZER']), str(self.params.get('LR', 0.01)))) + logging.info("Preparing optimizer: %s [LR: %s - LOSS: %s] and compiling." % + (str(self.params['OPTIMIZER']), str(self.params.get('LR', 0.01)), + str(self.params.get('LOSS', 'categorical_crossentropy')))) if self.params['OPTIMIZER'].lower() == 'sgd': optimizer = SGD(lr=self.params.get('LR', 0.01), @@ -181,6 +185,7 @@ def setOptimizer(self, **kwargs): logging.info('\tWARNING: The modification of the LR is not implemented for the chosen optimizer.') optimizer = eval(self.params['OPTIMIZER']) self.model.compile(optimizer=optimizer, loss=self.params['LOSS'], + metrics=self.params.get('KERAS_METRICS', []), sample_weight_mode='temporal' if self.params['SAMPLE_WEIGHTS'] else None) def __str__(self): From de912d53344b8049b9daf8bf89b790accdc75a5d Mon Sep 17 00:00:00 2001 From: Alvaro Date: Fri, 21 Apr 2017 11:55:45 +0200 Subject: [PATCH 02/25] Fixbug apply detokenization --- sample_ensemble.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sample_ensemble.py b/sample_ensemble.py index 8c70107..81901f3 100644 --- a/sample_ensemble.py +++ b/sample_ensemble.py @@ -54,7 +54,7 @@ def parse_args(): params['INPUT_VOCABULARY_SIZE'] = dataset.vocabulary_len[params['INPUTS_IDS_DATASET'][0]] params['OUTPUT_VOCABULARY_SIZE'] = dataset.vocabulary_len[params['OUTPUTS_IDS_DATASET'][0]] - if params.get('apply_detokenization', False): + if params.get('APPLY_DETOKENIZATION', False): detokenize_function = eval('dataset.' + params['DETOKENIZATION_METHOD']) # Apply sampling @@ -116,7 +116,7 @@ def parse_args(): mapping=mapping, verbose=args.verbose) # Apply detokenization function if needed - if params.get('apply_detokenization', False): + if params.get('APPLY_DETOKENIZATION', False): predictions = map(detokenize_function, predictions) if args.n_best: @@ -140,7 +140,7 @@ def parse_args(): mapping=mapping, verbose=args.verbose) # Apply detokenization function if needed - if params.get('apply_detokenization', False): + if params.get('APPLY_DETOKENIZATION', False): pred = map(detokenize_function, pred) n_best_sample_score.append([i, pred, n_best_score]) From aca2744046eda3b7cd7a04bd05a2ec4ae7aff884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Peris?= Date: Fri, 21 Apr 2017 11:58:22 +0200 Subject: [PATCH 03/25] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 52de898..1501044 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Neural Machine Translation with Keras (+ Theano backend) NMT-Keras requires the following libraries: - [Our version of Keras](https://github.com/MarcBS/keras) (Recommended v. 1.2.3 or newer, as it solves some issues) - - [Staged Keras Wrapper](https://github.com/lvapeab/staged_keras_wrapper) (v. 0.7 or newer) ([Documentation](http://marcbs.github.io/staged_keras_wrapper/) and [tutorial](http://marcbs.github.io/multimodal_keras_wrapper/tutorial.html)) + - [Multimodal Keras Wrapper](https://github.com/lvapeab/multimodal_keras_wrapper) (v. 0.7 or newer) ([Documentation](http://marcbs.github.io/staged_keras_wrapper/) and [tutorial](http://marcbs.github.io/multimodal_keras_wrapper/tutorial.html)) - [Coco-caption evaluation package](https://github.com/lvapeab/coco-caption/tree/master/pycocoevalcap/) (Only required to perform evaluation) @@ -95,7 +95,9 @@ optional arguments: Much of this library has been developed together with [Marc Bolaños](https://github.com/MarcBS) ([web page](http://www.ub.edu/cvub/marcbolanos/)) for other sequence-to-sequence problems. To see other projects following the philosophy of NMT-Keras, take a look here: - + +[TMA for egocentric captioning based on temporally-linked sequences](https://github.com/MarcBS/TMA). + [VIBIKNet for visual question answering](https://github.com/MarcBS/VIBIKNet). [ABiViRNet for video description](https://github.com/lvapeab/ABiViRNet). From 932c6409ae25febbf886ddecd53a341478442488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Peris?= Date: Fri, 21 Apr 2017 12:12:07 +0200 Subject: [PATCH 04/25] Update README.md --- README.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1501044..41b66b8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # NMT-Keras -Neural Machine Translation with Keras (+ Theano backend) +Neural Machine Translation with Keras (+ Theano backend). ## Features (in addition to the full Keras cosmos): @@ -26,24 +26,28 @@ NMT-Keras requires the following libraries: - [Coco-caption evaluation package](https://github.com/lvapeab/coco-caption/tree/master/pycocoevalcap/) (Only required to perform evaluation) -## Instructions +## Usage -1) Set a model configuration in `config.py`. Each parameter is commented. +### Training + 1) Set a training configuration in the `config.py` script. Each parameter is commented. See the [documentation file](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/config.md) for further info about each specific hyperparameter. + You can also specify the parameters when calling the `main.py`script following the syntax `Key=Value` -2) Train!: + 2) Train!: `` python main.py `` -3) We can translate new text using the [sample_ensemble.py](https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py) script. Please, refer to the [ensembling_tutorial](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md) for more details of this script. +### Decoding + We can translate new text using the [sample_ensemble.py](https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py) script. Please, refer to the [ensembling_tutorial](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md) for more details of this script. In short, if we want to use the models from the first three epochs on the val split, just run: ```bash python sample_ensemble.py --models trained_models/tutorial_model/epoch_1 trained_models/tutorial_model/epoch_2 -ds datasets/Dataset_tutorial_dataset.pkl -t text_to_translate ``` + ### Scoring -* The [score.py](https://github.com/lvapeab/nmt-keras/blob/master/score.py) script can be used to obtain the (-log)probabilities of a parallel corpus. Its syntax is the following: + The [score.py](https://github.com/lvapeab/nmt-keras/blob/master/score.py) script can be used to obtain the (-log)probabilities of a parallel corpus. Its syntax is the following: ``` python score.py --help usage: Use several translation models for scoring source--target pairs @@ -68,7 +72,8 @@ optional arguments: --models MODELS [MODELS ...] path to the models ``` - + ### Advanced features + Other features such as online learning or interactive NMT protocols are implemented in the [interactiveNMT](https://github.com/lvapeab/nmt-keras/tree/interactive_NMT) branch. ## Resources @@ -104,7 +109,3 @@ To see other projects following the philosophy of NMT-Keras, take a look here: [Sentence SelectioNN for sentence classification and selection](https://github.com/lvapeab/sentence-selectioNN). - -## Warning - -NMT-Keras is under active development. There are many features still unimplemented. If you find a bug or desire a specific feature, please do not hesitate to contact me (lvapeab@prhlt.upv.es). From 0027d3a4e65a809abc30ee0775c19b2e30709379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Peris?= Date: Fri, 21 Apr 2017 12:14:57 +0200 Subject: [PATCH 05/25] Update README.md --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 41b66b8..f950674 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ NMT-Keras requires the following libraries: ### Training 1) Set a training configuration in the `config.py` script. Each parameter is commented. See the [documentation file](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/config.md) for further info about each specific hyperparameter. - You can also specify the parameters when calling the `main.py`script following the syntax `Key=Value` + You can also specify the parameters when calling the `main.py` script following the syntax `Key=Value` 2) Train!: @@ -38,13 +38,19 @@ NMT-Keras requires the following libraries: python main.py `` + ### Decoding We can translate new text using the [sample_ensemble.py](https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py) script. Please, refer to the [ensembling_tutorial](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md) for more details of this script. In short, if we want to use the models from the first three epochs on the val split, just run: ```bash - python sample_ensemble.py --models trained_models/tutorial_model/epoch_1 trained_models/tutorial_model/epoch_2 -ds datasets/Dataset_tutorial_dataset.pkl -t text_to_translate + python sample_ensemble.py + --models trained_models/tutorial_model/epoch_1 \ + trained_models/tutorial_model/epoch_2 \ + --dataset datasets/Dataset_tutorial_dataset.pkl \ + --text examples/EuTrans/test.en ``` + ### Scoring The [score.py](https://github.com/lvapeab/nmt-keras/blob/master/score.py) script can be used to obtain the (-log)probabilities of a parallel corpus. Its syntax is the following: @@ -72,6 +78,8 @@ optional arguments: --models MODELS [MODELS ...] path to the models ``` + + ### Advanced features Other features such as online learning or interactive NMT protocols are implemented in the [interactiveNMT](https://github.com/lvapeab/nmt-keras/tree/interactive_NMT) branch. @@ -91,10 +99,6 @@ optional arguments: 4) [NMT model tutorial](https://github.com/lvapeab/nmt-keras/blob/master/examples/4_nmt_model_tutorial.ipynb): Shows how to build a state-of-the-art NMT model with Keras in few (~50) lines. -## Contact - -Álvaro Peris ([web page](http://lvapeab.github.io/)): lvapeab@prhlt.upv.es - ## Acknowledgement Much of this library has been developed together with [Marc Bolaños](https://github.com/MarcBS) ([web page](http://www.ub.edu/cvub/marcbolanos/)) for other sequence-to-sequence problems. @@ -109,3 +113,8 @@ To see other projects following the philosophy of NMT-Keras, take a look here: [Sentence SelectioNN for sentence classification and selection](https://github.com/lvapeab/sentence-selectioNN). + +## Contact + +Álvaro Peris ([web page](http://lvapeab.github.io/)): lvapeab@prhlt.upv.es + From 57f3c46d1408cceb459dd747bd6de3d6e78b0269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Peris?= Date: Fri, 21 Apr 2017 12:25:08 +0200 Subject: [PATCH 06/25] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f950674..69e57f0 100644 --- a/README.md +++ b/README.md @@ -5,16 +5,16 @@ Neural Machine Translation with Keras (+ Theano backend). ## Features (in addition to the full Keras cosmos): - * Beam search decoding. - * Unknown words replacement (see Section 3.3 from [this paper](https://arxiv.org/pdf/1412.2007v2.pdf)) - * Ensemble decoding ([sample_ensemble.py](https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py)). * Attention model over the input sequence of annotations. * Peeked decoder: The previously generated word is an input of the current timestep. - * Use of pretrained ([Glove](http://nlp.stanford.edu/projects/glove/) or [Word2Vec](https://code.google.com/archive/p/word2vec/)) word embedding vectors. - * MLPs for initializing the RNN hidden and memory state. + * Beam search decoding. + * Ensemble decoding ([sample_ensemble.py](https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py)). * Support for GRU/LSTM networks. * Multilayered residual GRU/LSTM networks. * N-best list generation (as byproduct of the beam search process). + * Unknown words replacement (see Section 3.3 from [this paper](https://arxiv.org/pdf/1412.2007v2.pdf)) + * Use of pretrained ([Glove](http://nlp.stanford.edu/projects/glove/) or [Word2Vec](https://code.google.com/archive/p/word2vec/)) word embedding vectors. + * MLPs for initializing the RNN hidden and memory state. * [Spearmint](https://github.com/HIPS/Spearmint) [wrapper](https://github.com/lvapeab/nmt-keras/tree/master/meta-optimizers/spearmint) for hyperparameter optimization ## Requirements From b2c2ade076006e47ee3dc29be9c1f64cec2c7d65 Mon Sep 17 00:00:00 2001 From: Alvaro Date: Fri, 21 Apr 2017 12:53:25 +0200 Subject: [PATCH 07/25] NMT figure --- examples/documentation/attention_nmt_model.png | Bin 0 -> 44870 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 examples/documentation/attention_nmt_model.png diff --git a/examples/documentation/attention_nmt_model.png b/examples/documentation/attention_nmt_model.png new file mode 100644 index 0000000000000000000000000000000000000000..e11000ca2f7628bd12634bd6c5a071b2480861bc GIT binary patch literal 44870 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

$4(? z>oH-+sK)crzpP;x17%L#AtoC;-0w4?|9(>!S_j?R+CN~25L--diCAqxT1+wCG*mhN z0`G;VCnzPTXC`OGz6!P(;F=?G13>zG;#{6{_A85nMAT=+gXd!?d+zx?4y}uN>q7Uf zf1fulbUU>E_8VbpS3kX3Ej=Q3G3)LGJ62FfgFAMcnF$C7v|+ZcZ6%;DX>yZwRa8No zy}Z3Wc${|S9o-Sx8?CH$avncROx>Y#N@3I!-5+TUF!xdxz~I^~OtIoxcz<)63&(QB?&wn}HQ$2Z~SBh|&bswx=8MDHzJ^O(m%lx5XEukxLawrbbdi494yZe9( zhZokIq)!ISR8WD@Ya8gfWCp4Bsv2DS^>t)&da&f1_2wN6#*+M#xl^_r3?;Ftpm(93 zv#%n1Y`c?>+z++6^71g@#ZVb|LuhBQ%U74!4^qOFa9R7Z@p;m zb~VItOf)`*8gcsYKOg6fj#7H}+9i!cdS?p}KJ;&rAxb%S*QW9??*qdtR}%v7-^S~` z{=qxX{O1hYthG#AbA6lbf(E-1F*;Uyc95NDzGjiYG*a1lURcn;Ea-R@_uhR|iHGt< zXqOev=r2f{q)tOupX<*rsQ#AO7T2DCcBO-?DWwJtR2JvPO4iOWjV5UjPLss$x`Hpw zHEoORYmA&!h}aEtFG@E&AkM0KcZ?tW>ua~3#HuT`KRywtuKlBOj$yHP^2`jhYpi%>1NKwkbGte_x%OnaL8|eZbBRWhb=yc#v48S*87VHtE&3>dur)+FHZv+$J^@PCVKA< zf0!)fzk&RqD}wPH=yNRcf(Ft1baF4naRQf=U*| zhIv2Lm#_@w)mz&be7>@?^!b3Ey?K*NWl#{@nZY%#TOPVvB4P&( z=j&+SpSo--+O90$qzF*Me1mZ4yLrObYZeb+|>@@GI|7WFlapUiR1( z1bZa>S70tKK$ndLRVEZ_$vgk2?03DX{{D_|R$Vp;QNO8S`uzM^*mLV-bWfAy6rX^A ztX-$lKj{L`dqAIMU zVuhaSpOob-@OQeUQHDlP#WI1wcvJ4eJwHATPRWSl3W>&~dYP|~YX>_A2Lvzv+la@- zadwR-NGzXuk`Iefd}(1JW`W04g_~}vBnD17q+JU4_f3ts6r%jPX3YB>@&k|^+S+00 z3RU@}()IC7^zR_3LLfxz>@*Ev)@s4{7K$=$K{wAXqIV2hlYkBjHh^Q;FUF zQffk*{Jl5y+1|r|=)!78;7a3p&8%@>W8o@$2Xk|nYoCIfGgbjz#k_thsKb!q25}XciJIiBt;3`_Pn_v$PbU()FKkNbojkeY;=V#Z9&Jc@zel36vd;$-PJ`ghpyfXViyXpQq9xqRU(N;&W?04$4a@rmvI!w@}|Om&MOW>S&w{d*Mq z(6Zy?;IIr*XWk?&&HNeJ~&*Fi?g0Mr-Ry1atS*dJY>UB`?zc zd#_S~4V^jpHUGc~3@%}3MY?hMj@Uy`zvaF6uA4*e%%EY=ev$-z$HuCvxt8~96vZLD zL6I?Fv9PpM%e`Ahu(kwyIcR+xP3q=ceoAiyYnibK*{E;HkOq`e)Ac#j~L!_M2r3mKc3X??NF*IeaFHLop}lSgzwWcvcONLqyK*0j zY%vXMeA1aGqYy>gDs9%Z@LR=yO@_-THp3a|LoxZEG>0Pb4U%Kx z<6T_?8bkl&JzSc6wm*(c#t}TPIMT0Zvq>DHNbi)BNiAk%$HkRCKW%lJdx<-c_9m?0 S;1@>%KYI;K^-FY}F8&92)>HKW literal 0 HcmV?d00001 From c9ea6d82e051cc8d173addc3af231e03f08aa0c4 Mon Sep 17 00:00:00 2001 From: Alvaro Date: Fri, 21 Apr 2017 12:56:23 +0200 Subject: [PATCH 08/25] Fixbug apply detokenization --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 69e57f0..93e7243 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,12 @@ Neural Machine Translation with Keras (+ Theano backend). + + +

+



+
+ ## Features (in addition to the full Keras cosmos): * Attention model over the input sequence of annotations. From 4cb117258ce9f0f0751fbdd8f223facda700901d Mon Sep 17 00:00:00 2001 From: Alvaro Date: Fri, 21 Apr 2017 12:57:20 +0200 Subject: [PATCH 09/25] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 93e7243..3249ae8 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,6 @@ Neural Machine Translation with Keras (+ Theano backend). - -




From 7a4d231745116b5a8c76116e18b857a1cc37a056 Mon Sep 17 00:00:00 2001 From: Alvaro Date: Fri, 21 Apr 2017 13:00:44 +0200 Subject: [PATCH 10/25] Larger figure --- .../documentation/attention_nmt_model.png | Bin 44870 -> 125450 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/documentation/attention_nmt_model.png b/examples/documentation/attention_nmt_model.png index e11000ca2f7628bd12634bd6c5a071b2480861bc..a34ee3a036eb0d61f42ddc789d4ef562d78e8cd1 100644 GIT binary patch literal 125450 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Î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 U?*KYTcemF#Q)_a$h!Mklt9QujN`;u6Q( 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 literal 44870 zcmbrmcRZJE_&0vpBiU3oS&7W-9TKt&*;~je5?R?hkr6^dcJ?ZJMzUA-$SixW-|@M> z-{;TY^UrhL_p9#L9X{7}o#%NR?{yTau6q9}J{3NKAXgtK%4s49dL@FODdD2S|FIqq zmxJH1&6MxUA(yCs(!b}#A_xQWKu$*6J!K>Hm4TMdL8F>rb3HdYen`4+CnY6`o}653 zp@Z&W;mAl*Zfb8ts+*Ols@UL&YQj?=H`~GyTSN5{hVT&FPC^ao$K!HuY5j;v6+2H( z7esikG6oR8Lk>@a(+>aDZBEB_c8eWOmdyspGBOb3KAg|=`LY=6dWttKAkLeTx*whp&FUC-vBP@_tCn?HZ!E*Y6u zEJHE_g_;rriMIGnbVed~*DJo#4CDbF3%l;GU6uW$8LT)J<)s<2ZzmKn8`OI!PiZm` zhupZLNkSa5il0>A%6}16n1y|0E}?YvZASoG_%`0=l=ug__|6_1OH zE7W}akck4#FEPHn;w6{c^O51<)s+o2UmvfNnbt)Dn(=Ku<%jaHDiO?7kFY1RaHkuM!Xjyg#;ZY6H`)D zSYz|^^2*E0Q&LmaQiPk9T+pP?t|Q(T$ICvKr!y}^z4m514N2f8CV$woFJ7T0e!Ol|2S zJp2L}z8JeRR?)V7yxm35;`4fc;iX{1 zbJ3-}!;bonlgU@^IVG7S)MdHfyM~7=GBeGcoce}__Sz${y?an(DPR+mtNisAM3^ zfsW40#VaJFM^Y=m{+9InT%TA6p&33}(EF?!cePNhfRt|~2a#H#IiJoy4Jr)?i>q#$ zI9BUatFs$i9`4r|FQPZX^PtW8U!ni}I?k-XkpRijQpIS@&nTvodU-a~uO&?L?=)@` zt#NvwK0SN()O=?7(Q;@z(LU}u^8uNPyi>XBx97{ffmg2KU%5gr<^9cd{joS*k~@iu z^Fn*%*x1-FsmrrypR>#_{msp?7U5ipgbN*RPRV+y6Cy)6OBdcB$NX0IDukxRJWt5(UXhsM8Q`ZfBXT}AAdQhT z?|acz`x=ctx@GscA&iLx7t7!xoMnRAZl;kCSGXBH87rtZ=oWoeHLcqq%R0L69leB~ zrVZaT7>I=^#(w|y*=oW;`uh9*_Amm@h;ai9>)b+B$;imiX4i)E$DA!J7Ed=D)L3KT zIiB|{&$fn=)z{Y((Mz^Qz5F+Mt4Lqb_g=CQZa_B4%fBgWyG$u{Z%Z#{9dQH3>C!KE zFVAT#j+nS*m7K#;vuLek8AwA6&kYftju%l`F-x~E-Iu!5)R5WU7BS06OQS2_UcG&ywe*K)Wn0cGt(DQQQAiB!@lJ)#%*U#x^yTQrkvgX*q*v8S` zvNE9N&mL)tk7SfmIm`U-XJ3Ku+M8(AN zb&;zw2J-4R;Jn+g+GL{n^)aY^6u&`DZD(&UaH47GHJDUZV*L8R+jyptG;O6|Pg&)U z(-V)Pw9R)oM7J}U?!EqYZFE?uhBLIM!RLF(NoV)q@IbSDsM?FiCrcgC)cboc4rx!c zo;rW3N=P2cy>~Bu4)=3n;&sHv)>cVHh33YMx!vQYrl!iuO0Clp65IfVH`S08plgehU(0!R_nZvrD!kN4Qv*jhVta2tR8P`7dOXj$s=6%;c+sCJldUN}~CKI$fm5{))_+?Bw`? z=!gpI?p#YS6gV7&j4bx+R~{y3>@;|{sTD3?D9fR<9AjER{Y68X_dSD zTX^>wvT5(#yLau5!CUvA%3HIh^2*9M;Xl2ne-k0D`wvSJ>LtDYDE09v$(TOf$SN*T zK-k$ivm`mCd=8l1p3H2OudecQwrHAa=$Sf?=e-{|oOr-Yy6qDb(66(-19(%fp~08x9aZF7hT`#fXPDM(;9=K07e->biefS^1ao;93(w6v&?>+ zPfKesmt1Qhz29cE$nbaF%i^LU2Ll5dr~&+V7SMMD-b_qP5J?{SwwWCt9ZjmnziW}Z z+bPH#fgRm(dV;#pk?=MScJ`IcO&ml*;(L~ILa)1PMo9@TH}~fLsPX+I0%Cqr)c&WE zxp&V$K0dy_-dkE)+V1&#DwZ36V;I;(MMZDx6tzYL2L~%FD~pMVq4}z?;$UGVB_(xz z^E`=3P8JguuJ*a~cD?dOT7?4D4Tsd=#01KA_4GtUMLn+KBoky-l-JRDdAxJ2EzIh3 z?c2CG0VoEuvnKz2595E|6Cus8vc67z{W_13knvX&G^AX7{oA&3P*~dvy?aupq3OLh z+E$6Rz9MW2a&lwiAC5PhJis9WVQ1s&#vE2`rRbM-1`_r7JIfEODQg1eE} zu`oP5Yz6H>sz+UBS`O(N&ol%k>6nyR5OX@nU`B^6u^1w;d0<8j8LtWF)u*sJ)(-U0OQu^XFBh zw5-hk%^R2J&vgo)WI1G5@EQ`}@ez++KYHzLXoydFc`2Zybl-EDSuTs*uC&0HvN#^2mapsG_Xk@ruX_x(P76UN5Hxu>xmfqNAb z^{$m}adHyi;v$G>s)Ma92RVKR-%C4k{>HZq7}V6sb8~a>&4W2=3)}8=(T5x3W$@O_ zsmT!Ejs-&lgKW`8QosMbzc^S*3C{yW+QZ`n@D!Y92?>c|uA!qIo_lXFNqa-(m|#ny zcI6P@(~+T}$#1X75FReH;Fj@;2~iP|+^QluZ^>`_l&|+G`c{2gn%0J${!;a%Udhf@ z*S|tYIJ;S_uu42g_uost$;I_>(e>Ao%L8UjbMu9RzrTlXzfbAWzV}AFHxypw1zZi@ zGXpl|+1c4|-k@*9{j|D9Nl8UbEe1tLSojO8HXl1K!XSKIm-9Jaf1gWj_ z>(KJU4ar^dCz8}HwFq^G;(KmCknN@<+qN{-~iV=Uq+X5DZnFy*o8NJCitB9%h;Ue+&!^#Mn7X^W+fUU#`o?nSj;dwZP1NZm2@MUk z8!2dt0DOB+%^#C}(A5FJ^c&PlHWRMxU>>hNO z{rz7bCG@qm%iXulxVgEngd2_52z~#CP(NaSJs#5GFGqzdNx$XZIA=tot#eO{%zli) zONH=$-{@#?$AYtPN=Zpc!77PXkG|vgyL^157G3X9*d8cGUJ4azGjW)djnfd~=*zeW z({KjJ?6%OdB=QDf4qK}ZjgG!_MP2WwBHPS(lT@(%Wtd_V6ckQQPXPlt2?uS|6%-)( z_7t>NwK?SE(U2FeenodeIxLu3U?Zew?#?$((f;_+P80j<+G8D^=fX6|_3PIgsdy!@ z5nvsYQ&Y>o(xT6V9!WboZqB!bpP!$bo0~rpzl$o3kBI5%8=MyuHje&H)xn-d(vRn& zGLz7PFdz1&e91&z=BB14-sdNo_oIvSs|cez(!{Fh8SdL&;t(N-tu2xt{%Viipq?Np zDLwznpFbwgt|CsGbcuFEh&nMh|qrY=zUxqZlEmE z_)bSPd@NKkOo?ae zD&8Q=^La<_UFui0$Hy`cy1KQvxP+agOVy0&zmA(Y5RPGoMD>RI2VvXT`OlfEo8$zl zu!f(S0tn!glr&->PE1Y?4h+o5qx`WnR$}hhaP9`Bfs(sW2~|&2M4--#xotE?L6zlM zt}ZPteY#u{!u#+l-iIU+4Xh9*tN1%!&R-qr5#KD9Z-*aUvcHy+jO5iX>V=)cCwa#_3G6GZsVfjVx20vkOwH}XJ%XDb?PQ3 zhv~*ij{kspfM9FuNrShSt!-Xy*4qTAIQmr%-!D$qe_S<^?quNPv%`#iygCE@1Ijxy06qWm#ZPZ~U%`R?T5!hId8TiYbkvm5<`$<2|6!sLEqe zWk0Q6un`!!DP!0h>Mjn;{KchxRbE}aZy-zgSBglBS;-Jr_lxv5ByS-xYOAC?I z7kAt8epqz8z`#Hm-N@9-rsZA03W&JJp3R3KF{Sh*I=sAJDeTQdLoX&+h9C1j|I;Jl zzBLQ@AoJ6wf`Wn}uHL=bqwR&eckjw(ICZ^a2_~X{yfoB_+DUk7AH_+cpTbueM6fhs zd?_qU&4%OEFK|y5`Wo~);M2qJzIO}^l;-5z-``c`4w0L$_d4a{Z`0kDTScD#iAzX`)(=5L zL&RSGQ&Ccy-#xxU$*Eq&`Jp%F=KZ0&`#s0GvJ3*4l4&!eqe8G9HLe7=^j{c@q^{Ea z6Q+8|!)z1s{8Mi3s%{_+Nv0lbC_TOLGV5PMT)1W`sKddY6cB)^(Qi!vRp31?Pj^AIVbp>^I3nQH*ekmOV5A})gY_&@iwLzHZZ94;^N}W%$w7Rsi|BO zdhUBGG49y`NdaqD@g6*Q0DaJIwCK^&=LJ5;Y4OD`QW`tEyQmIeV2}c+&p}ThuEK8g zVu{;lb$wlH`x^?z#~F5pkSnG+^MS9 zu=o&ZRn=a2)JJzdC?yT-L=R>aJlEFN*3=w`=h7eI>J(t$<}S|4La9X1%SaQbsHpA$ z$|fb9pPfx7>=(eIAq=LlQSaXP@6}4n$oRSUTSwHr+;kZGD)U10CaOW=-)kN<_W2HY z`_rdStC}Nv%F5y0OFPG}E#-@~brQ-e1=%gxkNZc3jOxX0m2#?`7lQKh*LRk>vy5B; zxw^TjK6n82WBc$hO_cYe)aIRAT_0+c(pO2P1o_BH zmX=DPHK4Wz1;x@^nc3K>nW9ItseObJ8IezKA}1$jQ0>&z)@HdDXODq#l*U)gwDRJ; zY7S4CnV!G23N02EmL^vg>{mKEx=(`>6Hfp*Q~bzMjiZ7wg7(xU2CzKJUwy zFU`%(pu}CJ7F3C$R{FoeU7q*JNBGSad_RBwWP1@F8rlVdE_oL}0S#y&?I7GV~Oa*h5vD(7Mq;y?%hYWZ=0v;UbeKf$mjU``;$JRwi0KG#;hk6 zMHlp|ly%Va`%RuwUlz)JU46?ai}d<+#SC>#O-nOlarH`4pSUTH{L-B%Cp5ra&vP51uuvpl#$w!vAip=74m*duHOOtg_#fBo{<43X| zCYza=0h%l}ZU7v&UtL`dEOvBwxW8jMX1em3K3D-b^soB{2KfGwKYiLaNgyftHs#EP zf|`zS=Q~z*{Km!xt(cpzs3?Guv%Ntz8p8Wb*?tg6&2wS(M3c@>!iC4#d*(()BT#70)qAz^fHO?Hgw-nBhRZy>psUTTwwcncp~0s z?g0Hq_&}Y2jUEMRjrSR_`UkIDG-Vz`iIY*t(QmhLbW9U_S>)cmwY3#N^fE5Jq+~no z^2}OZUViI`BJm>)_Mg5|a*e?azL&NP>&>ZY=~cAivgsuRd_~Ri=3D)QN2hnc+zP4) zPA?{Nc#W0DjDhgrm}H8aiCul2ZD)ojPPe&^y24WliHL**1vPWEMN{vP;{&)?XCHzZ zS~jj5TvT+2Zb(Vp9yf|MGU}TlLKy0CI~F>en{KoFYUo>VXAIUT-O3w6 zQE)(jZ~;6@^EyZxBEF1?A=w`E^+iHGuClVS0_cEF5_=5~;o#ta5(!t4aRXEhmw%J3 zlN1!E%`EJkoDTN(bW^>{yPlq&u!eN>^p^ky=tNvF5m{N;C>oJBA{I_HF6W~JL`0)Q zLve9&lOTbGbJsWi=;nG-4#yWRF*wIxzdB9I{MW_N!`n#l1A_)=ewJ9quDm!15DQya zTqGwY)qM15c;@iT^7g?SqUpW)y#^m&`rD0@lzWlB9f4aqbD6Znlo%Iw>AC2yAIr8s zvT?-JXPb4FZcM8`X|e%*rtQ1l{n)s;#rb(s3W^G7;NjPZFtj^Y>@Bgz{&>F-P|qc% zz(V?lv1)763nl&-HhAAsHnWhMsC?KTNyn?2Dr#wCv$C`#pP^1jF9}GM>e@B7e(Rqf z?n2W>-p0pQ0*K6A0KNzekUhV(D@Eivs0qLwj6DBVl$Ltd)&{e_s53LJ#`N<;)AXl1 zetqF{v76S|*a#;!f+JQSFPT9Z|HfS;@Vg!V($W8SU(}Sslo7 z!4E|-S`t!HQbE86wY0YnIX_xC!)sF7`YAMni}_}3-JJWS;3eV3b-ddzrT1jU4o(yP z)?&}nVIsuUgf0tn!%|JH51R&4L0tMV__qlI@%`}O8tcEz`*S;%ojsU_hCD(zc6Nww znm78DD?B{Df2&fEWT*VTlKBx?)VEkem|@_7k)Y;y>RnOXCPNc;}5#Ygr;OPr!p-iA!RX}B5bvi>nDw_ z2x6(%NQ;Ir#58$gA-;Bq_M*}a(~+{LAmDtLKpK-B(Gim-hcy=~=GZP3RM3%i|rVmAg?TNEY7@1kK`G{sUR|%?4|MT(cSk#0$g;NkvE3J!X}0eWqba>OY$-o`e+{Qn zb#_~-PC0(;*T@gruP!)<@BW#wp&2jQY~Ye~N;dwAJ31%pN>4dQj|yvXk?JrB@6=T6 z!=alPu=YUd-o1m0z~^Aic{ntLhvA!FJla2?`7~y!=#F1%s*<(#e-a*9dVT#g01Hlx zT=yx~2)*n7gqI4u9(vSe;+$QG4TpVVI@mb2GMT*xZZ2guf7SxGekCVJn*97)L4-e- zce#!0X~@Yfo<0?EeJ3aX*WOXbKUDUDX%yrS{Yrah7ng|=^A5nu@A>Ld>csy;X8;YG zfF@-b<>lqQV^KGc*W_mc?V*-*TXg9!Wp(MnGoXl;zLj#(cno1UYrfFvC zocp%R;<(HxFHk<5l2+IWv^=q_<8>99W1kPGI@qcF;6Z3avll?2`BgY<-M7T{T^NZ6 z--AAr@?SodpCc@XLGii=)**JP2+!=|g>0&arj|&L z#k^B>Wlp39ZyiOVHUlxI%e#+$I2nG`wYB(|Z=xkn*l*qhrrG@D)+&}2@tr$&a@5iu z&-;ReNJ&Y#vnL09g7F$Wv}U-Z`RAOR=xNROQrULc=Fgs9T-0A5*7*7M|6~C+g!%c) zii?SYTe$Q}E&4ynBYjg-hQ`K@upBS{8AwQIz(GQe(?f%Uo|or`Ky(Yz8yaSMdQ?7sL@j#zGVB4q zcMVZRzcCRJ5fM|}$gw1>NQLgsP9QMCG!BE=*M=!!LqNv?IZIytHc;%icXRZ-3lEf) zZ^m{VA0LD0RaH`=Q6*f4E}6z{&1jEWpauB$M3wA_HU~GigZ$!pj(%Zr@q&Vh16yVx zp{kr59K^uTu*Ci9y?ZVF55~{VK5J*nFj%xKY|qcn1NbZPeIs=?N3<4iQ^{aG&HSGN zaR<~Q-3OkzCUf^lN#w|s?&LEP5E5o*Wubw2H&g8lwg#pzm@c6XE_Wn}amUN6s&cZk z|4mdV-?z3U<6&UMK9{La_!W$dKFUq8CKAp?5nyMgr<<6VG&VIcGB6+r z!PTq%BZ%x>W)>E307s3eZ(gCCAAP+)tOExC>XcG0f=9OfSpl^r!jF!Qxb!PKSNdQj zJaP+5=AxK(QI3POv~Q4@_76uwd6jD*_=4s}OG_I$Nw~NS@8jfnIqm(@Z-Ij2c57$0Y0VJQR*`YsdL*$;ZXFqDj?0xpu4tO%?8vuDqMRXI61 zDJpgzeJ9aU188MplAe;P5qSesRuo7hp9>3`w5w|cECs<;yqBDC@YvbatH@*9Iy-Tn z;tj@q`0znF;m%beqRrn`YAx%`KLril;a1A%Khlf}g+Bq+z_wDbjhZOqH#pbTfZ zX}Dl=A z@8Iz8K3e&QP+<6dRM;pv2KEliLiQCEH8tZJm!*{ha54c{oac|&pSn*(E+dFP@Ky*h}*l*ZJUtizIh>k9r=*pEcNVJIN632cnDRFLkgSB&b zAGPluJbd``qlBl$VaDL93#Gw*6*_(W-{+@?pxSM@e*>ELl*C4qdUo3#oJ=^n;GqB+ zNprg)pK}FDEjI^8UVgsVtDQyWic5IID=Rj~rzrX1hyuQT!C?-h@<=EOA7WTDva{Q# zr@bfIgrctaNspCUUP1 zJZ~Bzx3z0(LOVOpF~Gi)kQ^I3`1`jqGpSC2uBol9=#o~i0}v*-51+%jnTOM&opVl~ z|GkaELJ86dxPi^U@%!(FvvmIW@$Q4T23a#LI1ZoN^?C>tnFl5+?9hCFEnkBLBPTb} zNQDyy)e?NqwCyY7=?sYPtcgiUdL^Z58n(4{Nh#|sqiQTsb2ftii1oBf3IjUuzs&xCZwxu`NUbU)&N?_6jI z7}CQ-Lm*u$vXh%V$d>O)-gf^M6B7gO1h^ycAHY5yXDGECuNziKu#E}~m* z(+?2Y>f0*?^IR0(c)WA8ZQd3Hx(v0Ux`Lphe4^hXWw!qP_+0k^w)f=+2kIc6Q~b)8 zn_pPqy;*4wTc34UFQc^71@Z`545O`E@$N}I9-O#XaB&Z|WbhIcTm7kwclwZ9BU?4q-X=Ncd(4%Ql7D>jY%5L`sUV3OdX2#G1TucP{gJx}F!ca#Y z+eLG`>ujMT8f8vO3$)rVqR6wCmzROTB*Z-)d`=k2{a;7tHN1CaBGeo^x?9}&3tcJb-6UG zy9G{jHDE6&95@JRoRSz3k`?C*J)o{dd#wP}zH8=K)KhMetInKcL; z3JU32ScjV!O4dAOP-{Zb_YM0MT2$J_hA5HvV$W@B=MzUPsl~QL{q@xwwvk_tO_Nh5 z6MBzF?G9y)^=7Y`9+ubs5*rfSwYuj?HZ{^8(m{fIBx@gVLk&a_IBDV~(jb!9K3i#O zl6lyNsu|AwXntJ(&l|fd5 zoPy#n>5R`iA`AIMMxG=U=TVMadk?R!y5v}HA0so1?7#ER=IUQWt-LFeeCpgtgXq>y zNJ=f;LU6tRGVqr@P*pVo7EwL5wzk$D#@5r-)gSN%B;}V+s@HDAckmFX-@17ialt*UvFE`W~f4J#|)6}VwQ*4(w-66c6KhV_fJ5|1gUa}?%xs6T6bJWZ>;7xlI8I(0p;nh<7chhqjp&x z6Hj`F9drL4;+B#)8dSE=X*h@_+(eLfl+(AzC=r8O@$Umu$A zD3Y%VJbCiu)9|+yU2>CWHZ~zyrA>savHaD=#oWBSusd~Z6CZnccmOO$Ndyg@@O+Cs zPd|M8SZ~&bpPL}SJh}Z|$4IZ*DI+it3%?-IG$6PEpU3lxArtEZW8<{u(7BkfbX>@~ zDrFt)@0&V`k%kKRT%1AjDX-u3@87B!x~UafGtc77s~f^Lf3M`o>)*c_ZOI)!)cuK8 zjuv5f9jJyGBmFcX){5`(JFUk@JDvNq^JcT~7mrbqL2*k8O-ydnZP#*}t~Fo~z9fuYV2ch1>~vcge|~bIn+k;g6m?sWtB)9QOzCOe6XF2+mM2AuZ`s z(j9WI_La4@(h6Gs>U(rjL3qx`1FyK=F`0izTG9VNJzec4`I=;(4H(I5$;;0^Ey z2-U&1#K0jugH&g%H4VDo*QbNopFe*FDc*!DnqCU5j4JWN=>{JuR#t^I7D(W|SSLwh z9; z(C!qL0|fgrHFM$Er}Z!>%DdyG{Zdm^1w|MNdsx!d#8zxEN5iZu ztjXC*w7$l-i3PAAs#y{Wbthl@e?@-qyA`f!gj^e+;1-G4rXmhUa zDqP0I3s{75Z*3d68tVO;8mlEboZ(Wk8&|H;Ou5+jp_2u*%GP!?q2r&qMDUH2b8nse zT*KIF_s~Gg>NYF!K3Qd}=#kWrn~Ndk)UVtCzBdLWZ2Ne3nMKsX(h@>ifLy^NkNj!X z{c#EYnD5{w+$=D1Huh>48@tUX8-EJ&^9TFKF_6oXy@t@P8^WbpW-jdwlIO*(xlfqo z7>I3wI=xk4<$h9bvvcpK?QQhvjykW?N^rDcH@+9%FuN2%r1iG>qAq_VWYHUk3ziHG z50B38Vk+zWzC1iX^L^y@QD&s@Dn|JEGI>_Tiz>c?KR33j!N3lQOg9^|cXM#KgMiH9 z1H~innzX9iG2Yi!yiBp{)YRb<80hFnAQLJ^qG?|&F$Oy zz+Epcyg?4j)wpLnX<40S2sx3Z@`WUmGP#{n~O3ZzHd~*Fkh@u2QGFH+8k;MZ+c#lMsoVqX^0A?@W#59x|kd0kmynxaI z*PoxsIl6o1_wHdp_)&f276QT2|G(Tnlr1d)E0tfr>Q>q(m13u4amYf$f|@n`eIT5? zlPI=pvcx<%D=RBH`d8kge0PI-Ih+jX&ILT9S6&acushnrrk~SO%Kvq9C3-6WMqTW> zlIL}dn;zH=N-hQ;rv8wL>U`Rb&8t6P_2|TAsk=gqiwWUJSb%NupuFHVGYEklLbJLI z`;Es_=2ubS3RzU}AC}X6E*87UV9sRV7fSWH_*4h9{iFCRFdgMRT>vhCs$W!CNDFq2 z(9&~r^UR3PDpig%-kaYKL*$qu6*Bv6v^iWk{W0mHt4d3o1w#9=L*b-*pYMeA^_$>h*Seur2xY&>=&T9S2$Sckz)@+mL>7GC{qWDskRb z-NHm1@)SQ+H99;z95Ph@h>i-hNUjqo*xPRa>4Y>v`{ucnho>imLP2~BdjFX8JR~|I z0z!GPY7_O(Db!r{E6{zh{#ogwVMU^Qik0ee3MO-r1S!eULj6OCE!+rh5fK%I;9(IAFmUFIi;IJ? zEw)X`@!n&$5e@n_RAwEcSMu#_!1ta!DgB`d@RxH(9#*YV<_!b|ArX3TAnAQpot`c| zzt$2=bb5NK1?H@l7DR1oz#NKhBjo#oWTEkI)R0mSgCVb5fIU+L4GJVoNr`8k|MJZ*`iMy-22`W)V9<20d zPEQ;4pLR`7z6N!~+uNJ;63yU_5I_HOu$)LpNRX}R(PSk3kBktaP3h*MaI{+D>T}jW zv2D%q?ArCK;?@#9_EX1EYOCjh2z!^UtFi6F5k|`Cr%!YL8rS@+$%-1$o(hhf{bN0> zKCQfIzIx+_hca5@AX}l3!(?L=oJU>GF5@b^yPy&)*>9QevpEaXJWd6^y>$mbBXk5O!$#DYjM9_Aacj4hM|9&F`Eoj-VCZ)VnPRR%Bl;lqbZHHUEc zA>xThv&IGo1+{V!XV!q)?e1P3(Z8rR{u$yP=H~qIj{!ACMOs-{K(z4?kl&MEC6f)- zD&MWcK+e-Ix6#nj(o$6=1mp|*c>Z!iK(>)G;CI)FPZ~bo*bR=4B)k}KP$7!_cWrIr ztEqoVgCAL-jin`v+KL6_bDBA1J@roUJy%(FvZE%?4Dcuzxw#=1ru5h(7QJFhY#Lq!p3 zlQ=JvI0-~|Y%ScF%FKz9lUJyuFXnnfg=uCKqpB{jPjQt)ndhv8Gs} ztVb*`;v@+;6H;4{RI)s@2lLj^@tPjtp?=J8pgmh9j(d+r78PPrbY_lwW@;8{p0{7Yd0%_g!Sr+ zT1aB+>L#B3AcjtY1_5#1cjI^MM%WG7H0Z3l6~H=s15QSOd~I1-S$aC6PgYl3>o8s_ z|J)nD;rzML%IzyCP|Ndc-2KuMKhKVzh=#Dr=kfyOYfg)E+`02_ZH;tB?`wHE!~|&a zeO|t-+ISZVe#wu#e@9(xX%I#+5rbqLq{E%-{ijwOU^WKMwrFZbmi*ernqGNdf7jh_ z49h`Tfk`>R>pNfn?hhYQa=pOxwe*v$tbA-rQulFW2FEvsq<4qGnA+|(a$Q-fk>~E+ zzw7J#{QN+zLn9(EeW5BqFpV;NX>(IbBUlL&JwxszAegPWd)WSrIV>3P`%Txp8~DK^B{uiVA6*nDBr>Fu6~x-gphi+S?xDWmoxZ5OXhKi@|=ItJw zd#0tNl9a{5;mpovjlqD(LiyLP5U+UbT>Fvm3ym$fjBUS09ww^n^A^Wyjay7Z@36qRn*pwlV*Sj0w+6rqc|InBc7VtuM$}u z2o-~s$N5MeLP&fxkHJ#WjPQIRD#6IuG&6H~vcFD_p9QqOd&$GyUGeYP|MNJ|?gKJh zXr{p;35o`v{*w+{=3rf3y17x^xB=ZER`GL}4<5filE9nq9$|Gn&wCAl`2*0{BwW|x z{^$yjgz*Xpzy#%2bJ5h^h3%CWqQNaUsHmFHs!J@f|B$fEp|O(V^Wq4@7{*;zV>A_c zAYb^nxQ*WWB_rVdfE0~^^VvS+$2}PtwCIl5hKOk!*1c~{*P|zaU_wq6vS;lD1)O&h z>TLQy<&F>p)w$}2k$08y2=iFj6r|fFrsndkYjq#YjXHrA7-5F5nZ$3cYHgj<`cW3L zZ}z{E!P@}UL0*phCM-l*+4IAHQ)8z`Fx>}77V?BGu;L$bxO}-(-@%p_S zQ)rJPU(_pcx&uw{U1c-W$ybAJjq3_&kUW6^fW3XhQrjp*;QITUCTrPFVusO45SS={ z7e-4%Blq<0{pHW*CA#KqucQB^^3owlR{m9Tzl8Wx#&ST-@2=8f=`RGYp>%~o< z%evImDKIC5o=tqtylJUry!!fl+p^6eB0PMMm`&zkZ?XVIKyYwJd%F^|l+DwpF{z$% zn`{ePF>Zs$2tsl!L7yTF@3>?!MXZ+$yc?eJ|$3Gp(7LH2Qo4; zKL7KD@%GBlcKd{oD$B>PgK*W`4;HqBzx#imGn#|+@cGQ>vUkiC1l~A~FVUUXZ+A4p zO6qx$6jhO{NO4fT$Jykz)_t`(r|M0udK|=4`Si_)H=EI3X*#KFR8m7X_hQG?zRuiM zChM+{w0rL20yEjEs)yU#G0*=hGLvfLdbAG7VEU$ty}V;s8>hkw8L$U;Ytf~_`~n|5 z#UB!rF2X6`SAcd0o7vjXy1?+`eTVVi-EzOERpw*z3-Vv@P6L=8FOiyXOceh~rxXY?+VSXMEK)(WpEExm3 zG{6SA^_7$ts;a8GD-Ggb$2TCq4aObOX_oNeT=-Y%S9BuV%U4;qJCE;d%bzsKfj6cE z$XZS6TtJ?&@t-14GYK89s?@1wY7y38F0_?!2`TN*?yW9lxI_H zP{WiH=Iht70Kp{GG}Q9aQooIWI2}C&#oZ~_K!z#?TCP-{=&#dF(?0($t=Igukt3VS z`|s6m%X_JAh&cc26)DCtLf-1Xr`~|csB4kf3g7Eos5fY zQc_ZP@9qQtE>n_cK*e0N;uL^(c236w?f&pZD_or&7#;jz$rmecTUiK$cfkw^t$LGN za~>IhL-xUJN4UpFuT+!#T)1Bb&`(K4D@@PDhql6`1_Uz(hdL~uH74Q}$o2MX)N8=M z^IXVmL+6Z7j1 zN@UJ9tl(VfQe~Z-cwD=7Z9J9D7R`HSu?r$y=4NJ}>zy4Zp^SG^hPH3L-+8i;9r7su zF$*(u1f_~M1O#}~?o&kuQQR0E9W@3c*{c0Ih~T;D9TeN7oH$==v(zy@2`FiEJgQ83 zX=9^!;SvRunuVopa`Ftc>$r)GqM}|v@^|aY$z&Dw7UY1vHT8tSgc67{!2iIu!zUn+ z^ZW}Vxu_vObOhW9utr}PI5t5^U+P}^VGC#o!kgtFvX{{GVxh}GI2GU`D`&n^NJK;& z$@v!q8gHWBCs1l7B|rXJ{yjFPBB1yPOLs#5&)ucS8Ao!pCm$o66ed$BwzcMx6)8jI z83fSgfmX@O`&yWonr3X#6iO5ZrpN|5>O>eB6o*;Msn|h}p7A;~+@{jdH08Oz(4Gi> zTx+Ww=-QCKe5gcZ;{SySO?lODa@KeWcb@m}+`$aE#?9ZMY@B_9E$46&u9sz-&$;pC(HMv1TrWp1g zQGApOA3ErP5ou|a0XiDT4h5YHCbzrU$+GZN*iSUjX#Ts9^l#t91qCS);M$Ny$g!!t z_2$ZE;75eCi*yvGV)EA z#s5YD%LYSnco$^qaYGUyirX@={N!Zf`zsEZx}+~5Flaa~;-Gc!^us=Op;Vjxn`3t=Xp)}w6Y zCb3p9tE78bq|mf`WTp%f#@~tNisx6SnEIBETpsXwwE9Z=U8(08(IyzR;PfM(PEr&9<9+wRLsC-kF$~6b|ELyuB|#tIp9;LbC3| zj|Ri^KR5lSm9?cM_(bp*X#o3%v++ff0OpGy^@dA-!TQYfB@NgNOiFPWcu?~`fX*dX zp(xE6`3@7xS-HzYH8qGyr+ncBsiHbF^Bx92TBp_8Cwhu|U?4)Q6oHXj5L9+|cft7y zl)WLu^=A=I3k+K+!1(YuWOL#aUcNl68H*M52-9BM-FmLnb$pBEe$1RXg-Xlf`cBxJ)ha z6Q#?Syn-RKxGW}6>J6Y>ogdDmJ>qEY>D1Azk$dA-cv5cA)hX&^!%-wjRth3GjbGx!Y*#YW$20kd~?=DGn>hX7!f z!!1@MMv(vy4-8zmO3KQB6^-n#j{=l{bG%3&@N3!p;4?&tbIBKN{|4)Rx55~VCu)$57vzf z_@KKBqMLn!k#KP_F?|MNkUTh@Vty?{1pU68oZ?TL)`jhMrPzp;If#{j=1M2wQI5J{ z3*5ru;+OEZv!wWXx2b!=drgG3vgybG)}OEBk0saH=@%)&_HVLA>tf;~ZYu#y(Z_xQ zEv~Lk->r7OQ|Fr3L2^M>{@;6ocX$K`+vkk2zdc=lmmyz8>)NhXT!2%o$T=2eMM3B-FViP>Tl=NrD}eXgn! zl9coY!mRla9piklgQpgD5>n#Kxo+GJO9t~zTfx0-}fEgcOTF3 z9M4n6{lD+u?{{6-d7bBZ&GZ)lRM-WSt=2|lrkaC?M|H4_UBl_jpK*ci-d>hmC0K0$ zQ9~{v&Z>*Tx}(Ddfa(EZe&~|!B;h0lPzt^Nf{6=Q`7JHlUS9hn8=(pM6V0SO@ZqGv zGqGz`SDX1ST~Ki}_|0;ycXRHiL+*I$+iq8Xb?*nJ5elopoqp^2sqIVz!ZDh;9~TnW zjoyy3=#E!Ou>JiG^kvr1Y~>!Lv0siO7jJN#fy71DSQEl8n&_iN1qDnogKU)Kmk)9) z?dIZYxEzZ+0)dDCO=j&W#zXg26&1tiB-@VT{228gy-6BKP~v3{pW3R&=ZNzSMzcg+ zz3!E-`|Qk2smmwN?>&MiqO*Vgya@a~{35m`HW^rT{jXKAey|13_FmP}3Pm{;l5{DJ z@gB#9qA&P_AY}z|TUT8#NAq^5(ia>tR4u^m@jes$)=piT8~Tf`7tErBQeB2OZ$}7g zI&o@iva@hT8=pK0iBi6IGR{M&m^Czlmrs6ZZ-4gY%|=V?9<+lII2Cx_kP-GXye7#k z%#Yt!XAtvZpKR~EAu+J9MSX1)4JwaSX@&hhJ7+r zZ{51bMctHk$9()kyv*@(!46p;o{BIOX{bUo>!AYRtG-u}XKvfR9bxdS zR1lc1u3t*Sy<0jvf6mMdl)9#B3j=+tbRQ+X`$UTbSh#~Jy+2(Hc3RdxVQ5*B?%oAa ziYQtlcH0&gjW_y^=(fAM&C!4{nE!4&A(yfUUOem6@~M`Fh5-_7`g(fT{rv2!cciDK z-B=#o9)46o^;x8#RNWVmvr?s0|6-;EtP51BVm}Ckz!Qu3hhTH|83P*kM`$~53Qh?D z;|sdKc_FZL_xH07&&F*9L+>MkUq`@&T)`;a?5?&zCjgMnG#N|0dL=ZYpua3Ig7z*e zYa9TDqvLi03TO1fb&emGmyvP4c=3w6`<-&mnAI^Svs z>1__S;ME3A-cw-M5eR6iI5-GJHuik@Ku1dp9L=yyV}ADjZ%}`DA3*f|YD2BOBUNGU zeXbFn=u@d_VYH4)f~f)_2G|`g`gvntF@Be%*Vgg?9c|cg420FIgv^JX;)3__Z~Y z?rqWgakcqAZQ-3a|lQ1_R~CUhJmrRUHiV=)KxjtbFfccU^z`)M z&oS+j*nN@m&EEcN$B&%oS(?1pbWe=T({Tr zbVYtN>c`B&0wahmAz|Sd`4&iDLE8mpfRwU7J30Ty?TCm7Dje530VTpAztx1Ys-91u%s>r~jjf#yY95DRg19z|i-%She86DCb?1hu z4)wR`pmgr*tD+i5t1kZeMOtMi)Nl$yAWfU@pXlb-+m8!VJw(1MeIW##Q2wq59mb3A znFq$wT?)?>9(Bpf&24@A7S-xxj1CJ8-n*s2DMjvwA`_Rr{ycdSF49@lVqsFuk|T#e z0hxOhAjbI|^ylH@LP1nFVsk@@K#U*$p}-ztlY(ri?5D^=4>#OM{Qaw?r}e;lKw#yc z7SW@EUU)g)>9I(>WuF-i!NI}w>RauTfD7@7&pQN7Afr0}!1T8JT!mP;Q&DQ3c z!Tm#Co}Onw;tBnIcZ0^<{M$^!W1rrzX0jCVmnK2U4>~fVLtv_ukgx+w1$1$Pre(a6 z;SGI_Za%XxLbB(G`zxlh8_4J_nBsCxRq71zE2?RAmg z71K=fh+9-d1Z6v5|pQ(WIdz7k}>_k;qn{N((m6)M=lGCv$1H1tn3-a6*5Gg2Sjd zZTwY!VIi@-@KExmbZvNCsQLr!rTK_Q18=T*e=4-ExH2m%FOO(KCc?4seEm8hAcDH4 zPK1FgAdFI5myDC{{fEQ69?Mhu^M5J!{{36KzG8Sv?x~87j_35p81XSsc8S>0%yiSF zCm6~=0R@VFs_b)ib3=dJ^YZ1Wh={oP_ZkEzFs39V(7Z&`wjT$B#95l70%fw^y=AEx z8Gd{1wmN=w%nrNp6!@d21raZVZdb5D^bx(CKKJ6-(Rfbo4cMSV*Tc~8)z!aG_gJ4= z0`(dj1yG>dP$h@-XSy8(LPBEV0*$bZtd4SE`e?rC^X3?yu3$lOT0Iw!Hhb0MiG`iO z7>J6;5S_wteb@XP_b1yLOQaX=B- zFXi@cpnL+}dCb<9sL<=}?G-$*pNRm<7s4s3-h#T^tl1IjE?5p)oIF{0W%dkUxbF4K z!ZbM^f4z%1`8KOjyP@($ZUpN${{DbFe%NAjgB1#A(r=BT7k39q7$;{07>NQW;T{IM z1pD}JseLf48>;fV7S)LZB}4v9d!6*oBAz_U3P@4*_qHAMzFbp7c=C*_wCreh)uAUZ zL)fG;^B9DDw(=f7E(O|2uqiM#r7l3Fg9cY|t8eTq!gX>i$(Vc3c-DBOIb%?f={Ll1hs?!ST&;4do1X zF2ar1o4t)OQqYaX+}INN`{fit`kh?M)0TrC-!vS2h1{&VC^CjM{DR6U&+k2NA-M#b z27(%YEIy{)V$NYBqu)3&h>`?m)sn)a@JE4V6RMcseIhIe(=%YM+{g5e>g&6r)`6e{MIkC%sFgNe z>7NLb7JuLYIHTU%y}3~fR-uzg*3<+2qOD>w+t`oH@Ev$)VPcS!T_qU#*7j1r4_Ai2 zR!aROZ9%9H!&2S=10ktLGUZ#cNY4(I+X6PTapZ+BuhkDc5 z+4&G_Kbczg$rsO`qpY+SxZK^`EX>bui*u_--cCndC|<#(A57;~B+k*X38vQ8{&Pbr zf#>OwSL2|DDaq^CH^Z~CPJ6%a>EV>jy8QRYhn=R3E41fy>{Qzv+{a$oNNaO&JZ8@L zGua+Kv|*I{9*6$H^xYgB&Mq#>Z}tV|i0!eHi+UBLBzaU<*xaQ&S?8goS^lH+A$o%K zEx*Ks`{V?zy4wjK-n=}wxYE~EA7AgP??S>mej;S;x;J6@>>R_1rH2+%<+O#{j%hFx zb|{OEY`pL>KI?4be9q<4zNM+h*{LC2x5oUy3Lje^XAT%xw%B=AjBvHah#&y z2E@cL#4d*#>`y;#pr?1r$f!O-ftrz#QF`o3y^~Y}DipP&2=1`4ILxY1k$p4D5r^bR zLji1X9u?~|azj=OrJ1td>L2Vf5)u+4$ttgqJ>8F*6Oa4fQTkK*cgjC(a?f*j(}KFQ z6mxtb;}%-Y<+n*yR<=lMK6D*5?B-zFoA_gdc-36^J~IRT7iysK5~OaB+P_WNr$s78 zXD7Q-)OCpET$|w$-NY2@BB!tSNa)oPF44pt9KOdQas|0yB4{V|qo6Ne!D>csxl7^V zyrU=luyBKjlrgbgV_&}}#l?+HPq$yleg1qRTZuZLew5rU0Xpw1b3+n+N&6G;OwKf? zaKN<)swj32j>e`YKz6^k7WwVcI37gK8^gScLT4T6*N477P-|ddU@HOUI8;wa4N#-c z+^C0IwNYv0&o;4_-LTSiczX{$bp&g`^<)80pZ;)488`={$@tV%_)E3v_U#oD+qLIc zi1ks?0|!!u%aT)CY!x3dD3uZyQqwh;c5S&0zU}H-ll;}U z$0%Gh>FMWGb{dP43p!t3a5)Y~JT3IRx6w72>#sWd`&FiWX_f7bGxe%j>x9g*)bgP} zGu{2CX;kdB2g~vEke#*KF;kLb89qO*Kp%Py(rw}8PJ|mg`=ZJ^-O8=Guz9-#oO;Q6 zQ~l2I`$){%ZzR~dL$}7Ceq8Ht>^Zz{8#}wpF#N*m=^&4lDVPWG)a2ADh~Du2k5y2L zvx*4`O}*FEhNjp?1VuPOl;t;wwd!KsFm#5 zlP6C2eh{V3tv-pPsHmxUAzQb5_tv$(xs=);pMU*|5SSudYdzSz(pj`suJqy3i`Iws zt6r1b20SGSeOIPA#R|3^;F33CT@M1949p9hP06HZ_(jvxVt0-R8qS=Mb5~45l!Oey z@A`Fi+K|e1b81&46v$GuCiOZ+?DnpmcwHNgSPJil7EShD;=_E1J2(mV?KLp9gRM_Q zE+5_2rQojWwd zrxKErpFDabr)&^&-|N~7RWqKslG@9StTdAeQqf@ADduzT3Q4)r86@f?d_K?UDFl3h=mNucfWvuMqgj_ zqgzpSsyZr)CvV02odW<8Wj5j=ur?@dH($MzaF4Q#&!415eFB1Q_DRtlZGh4M zw{~=Npm#QvEb@&Z^;Y|62v_0XLAf&i>dDZhpA=Q+&Q)vVr$xnamdHKJtvIK4_?Th1 zh*<8>hps!-+4Gx`FZ(usRZayBR|LI-!NI%lf4~<2k_O~ylUjyAtiW)&xk)AJ&cP=G zhHFaj4P@%&Uim&Zmz0#mgQ!sPrQAw>YiRumksWxZXdpnG zW>#?xqGw1|@y=$@b?~x?kdOm9Tk&om->XG@iYd%W3lpu;`4}P!k`1~_AH!LM zaUe#Y|JEXOQ}SkHWIM`GkToCKzU>Is$%ZsChHq^jCkjO6xohAagI!Yh^mKapx>Nus zK}5%mJm6;WHV4(|&vP-SAuYOK!A9WB`B@5_SKDb@#&GSdA_u@(e zEPvw&dKPh}pqK6HH&QiUt4k)jTjG*1(?5r%`Y+5?65 zk*D-h3cx;p{`Bejn?b=LA@pt*-yWoXUOAZVxzP6UaOCSI9U2Skk6~Va6(+pqKim8$ zsogI2xGLK7?Esi>e>{*#Bl50lYzWxT?K^W?KKPW{uvmk+V&QN3!}L-k zJcOFzuI1~0dgBJS?p&TMI7Sg#&qPTMkO*8!CMA@0HW8Gjjt35u<4~gF6zPS^8x@*~ zZ7<4^Q^v;V_nACiC&Q-84Yk)hfHwZ-Vp%nU7=U`6FRUE)u#hHJx=MF`PB;7~7vSJQ z0p&bezY@m6)?tG+Me%f|+^xzVw=aF|MDVCl*IFS$S06r18ub2JT5A50#UCKGc7pU0 z7`*s@Cs0|LR_HHg%S3A8}mZxs&= zL)RN3`P-3^FS_n91y9A*G`?14CUWuQ-4jUI{6DNh4={Td2oC~{( zJ!aS7U&y(CV-=wS&=k(z;7C+-|Md#xM8~9;Kzdq0}%>R2vc3i zBg5>oWH_>+WYXz0HMf;H*T$Eh4HR`9rpGWGfyM8@fL>PjQSq-&a&vvx7F~~h zQlv<(oY4|jJkfWPA*AT~$}co1V!j#jlS9Fa27`iv0s}R5-Ke`V#~ca~a2wI^du~>A z^w+a#Sql2lHJDZ%S{@!M9U;yv|CSN#&U@rGK zPt}6%xC=rsB=N1g{N;cz+WF@m>zhrb5)l)NSr&{{Mm_*!5uV;yDY?b2v2p-hkw=k6 z!?t*HeTBFxA%kjCWHWbDlO&A^cT`0#1Jeii;i3-%Efg{cf3Wps+0zs`(XcwMtNZ)c zFXncq>Wxy96Eerdk5C!tN7r^|#j`8JOccd`vt+_vVc{}t8hrWc%8I^~>?|_AJ^X2x zy#(JF9K6t{s(!@Y?+8yhW!T44CMNsXY01cf05lx?!YYa^^yt9EK51#ZN!a!6Ub`%i z)evKPUKQ4smT#_>0INgdhzJbg!kxFv4NNkK+me#-g?j&C=Mf1xd;76E$QgMYEokXE zj}MIiwuGg1Ke*G<>9E=0+P(Wwlk8AKibBjq2cd91t{Z#B%$PGyklS6=W#Bu8XbX7* zkp57tEaxx$&Z}!{TF(^OSXeIo`PK~p_qNK-va+R(wKz$~y+vVyYaVFM;X6REgprx* z=JNQpxi`X+zXj^=?Z1G&BOJl`U60tsLRgkj)nbmE2CZf20piccMeP}SAvVfnp$R)& z5FI?cywdk+3Jqrb2ge5QNULxXUbjSn3xq&|rraRQKVK^3Oz`|A-9;9}R52baCQ z8Kl|(oP$@K-{`u1dnoKPiK@Sge{{KpvIN%ObpHuS+UWoMVWZ|MouS6wNylC9_kRAP zU-Bozx_|}Ao(6AbI8R}8Es3K1q zRUsbS(b3%J82>RDS88$_(1S8a2u$#co;Qo>Vr7Zuv!yOF`}ao!6~e&_B1c=>c~`&4 z-*^-mz$FC*1*zh1X2g;H{R`)Tg$1{twr?tH+Rl$n86-f$Zfb50!GS-FJ-{(059sVX zj&jRtySP$A~U7Zd^cy?RA zlByvmv5_$4YI@aRf{%&}W_kOG)2Gou2e%X_Jh15c;ZdgA2i9`rs@P;KQL?F?%6OSD zqiJdisV+dX4ga|i6Bz=h6JYhmSzAQV9sYFeA0ChdK+FU97p9e*spiV7LK}bgs*iFn zyK`Lk-O1$_s24O*^lpffMmh5_ekR$E_J2pKy_IjS3l>Fv&Gx^-SzA`~=PRulm zemEx}z09yz;e$i!8_z5GsSPHIBvw_|%`l0er>AZ%)%MzHNM8Hv;o?OUJE-x3j0!V; z{{_wOPFbJee?@xv%FS#+aclY$Cjy-FJ<4nBNN>qL_>fd7WB-M_fq}K?w^XAwws{DqIyN=|>JMx_X2I7b{lKNB!NE6GRT&?1a&tw| zowX=C366@j-`|}CSgHT`_KoY1g{!N?ObdVYC}~5(Oi7Wsd}TTq1B&jM&z?oWxlLudn?Lt>9Xl%B7)eCza37U zdXKIO5_7S6`WQ;o5+{qmSulYwGR7TOse^HWN1nt8U&l z2B;}mzp@GnJgyaob#=w|@AoRCO+RTUl7Q%eDE4RZ-Egrjo6pkLY~%VWUz#L^mt}G` z`E$Pc&y-r~XOBrMt{!$3?f0!u*LHeNVrgVUM;a>e+@JS1;BZ_~gI^&ZfW`yK0Zzg8 z_BFPeCz7NDCufo?=0E2ce0}q6DF|wp_PujDXIap6_l)7mI2vkd&M(?$ml6F)uv}^o zDBr$yMa_WyO6rFL=HgH#6#@SP5EFeINH?)-rsjG-e6U9b3v(uqcxV>QKGoFNz*GW- zTO_N*)jus$vtQ@=KJStYDET|UG<=pd^6$s$%@63Sa3RJ=nKE1e(|@ z0V~7V6+LxJpwlqQ&szmsiFm=Zb>7=YBMjT2&TbcocM;bc^$(@Gom&0K5jYVZYEq|(J2B=l(GrVpOR|{B(bFU%k(iW9U4)L%#CIdS2^P(cbX2Lks9S-GKwAjejAJd6o*-Us^H|K zkcHMr8Epk7C0-7}8@G8>Gvcm(-Rby9&_Z&%x++OEw_yg|@a)Y@hMKdcuU^I-On7|6 zTS;VoP};sZsC{p327}RqXB4~bYw!Cr0a)Nvx8h@!xEabYtSk^~(=0vfB`BDz%5(n0 z*-x^sZg7{n2DK+0)~B18tZmS^&KgtaJ?tm^4nEp9AZg#(|6)ly%Ewzbr?>IRqDaT* zl`zWRAqHFpl_vw!DWNBTnQtL{G*Ig+D*Cv)8zw7|eCOwNkb}|DdYKR)Vid9GBF7}G zDwmORo|_3rk5XPiA+onklxBC#*027q0O6>43w@b}`{WX2*eX030dC}FURGJT41Xti zo7tLguWZ-!=9A+175CtqB%vnT?QG!oiH<+-TA0kr=xJ$fzMp*89jLlNH8FYi>+$@; zn}ZdCqx`g5$ByN`c;RZ1gRq%(d5nr^0ZKu`YEvRj7-^z=P#CsAK;8%Ac(_TXEYAaNCKW7LzJAbU){{6#O?;;0|h|tm3j|S8; z?-(1^^F;j5&5AAE2cB!zgR+)JrXvfh%aYbN6TL-zLUF|G+8E8)B_5Tl@87-4%voAgA!Y+;Lz13-R3g$KaD<$IMl7-vWF%-qlfjij z<@&O_q2V2b6sI8Y%KqSpKf(Rv+zc<>_nX^RN%Mc}+c-!`PX+zj9?c!C z$R$}OtMK!%#d_>=-k$1Bn~m+wEVu6~UM8K6x42{RyKvjCOVlUucwis}!si|D&}0{) zpw@cOW5)9~skr6qKcG{fO5JmQFTAv~A3bVO|J&)@(iXd^wUyjCy}h(lNlZ+Td%@LZ z{ff0O|8tx^d-t{>X4KW$MqR|_rKYAnXUAy(L(r*-uUn>O2YmNMb@XJ{wLM3T;@Y2I z`~JNgF1Yude8C(*NkFaQdF6^wd@KGM$q=TTp^U9jMFqiPbr@v2Rm_D!p@R|y0f>Y? z@7V-&ms?+Vsjf-=GVo27ZQ*puDZBRRDp=JYwoKC(@@NUmir>zCRIL!=I%b&h_v-AD zPn`#$|6BRO_C3U$il+H;K}IxMYag3{*)m1AUd&?UMoZ{FkF0@HX!GLjY$2Zr`BamzwPFW&>OkGmTn(^e=+lQCKL8X*bThWLattNdqW*_UwYim^~pA&|PLGQeq7J zQeOWAQtNQFKToR&ALF@vjM+d{2M`XFKGHz=B@Yh_xHvh%CJMZN;fD&!>Cm2VnK(RV zXR5pcV{tetS+bn!V9yfzV%y$$irK66rr_+K#k{&Ioi+o~fIVlm+J3a<)8BX7P*y%L z(AU69klk(ns>@$ua-)8T=iyJy@{UWsrW=d|>Wm%po5sq|^5yc2WlGCau3hTw(Kq$C zl(0-wz6d}JMKYR%Xy3+rt77aPXwI64{17^kngB!Lag&e&K3A;T+=VtAv`grE2CCJt zzCoD-+!JE=dG*`qrBy!4#KfxZ8&Q>S-k@_|Ubb@)z!Z;MY4S_bzW*=H^9i^=*8y+Q6Og^H6Q7c#Jgw--C}H zTcrGKL4Lj>5-RrX6Yh%YcWIa|Grf#@aEYJZ_}~k!+1wn*`=mA0p*zL6jOTa%a!;H7 zrudPG@I3l?{oT-ogY&N~H}vu?@*q`1Zh}>b3(zekIgr3-LgV*7j$Mwi`b z!`SwViW!5_RSbcF)o3eU-is;bTT=+}6UpzXuRjFGWs7#ZX3L??iI zp6>39D?v=`?C8e4@|>jPnL%_wv{e#|bbt0S^({USBKtYn6dVMm*DqeWbm{2PZG?_e zxpA@C->a;XS@6$1d!LmJ=EhwTS;c7*JXR30sUh@oBw z4gh|c-Sbl_-*_6&0NEo5w+PjPZiW0zyUh{IT~)hRwzIR)>j3-@1jNUP*<8 zzc3Pl-__iKoOat0ZML)bbcH2wh=SzPUl0;D`{o(XwtL2xx!jqrm*L2Iv?pq%;_EGxL8WZ~StT1!f zt9;GaNndR@#{uwLbF#B%K~9(nV*%8Keroz5zk45Vy3%O?Z?3%l8}B}(z4M%&Dn~Y$ zoOpw%z;F&(je|7+S=32WQ$@Ky2k&SjGey#U*EQ+f*rM z_2y(?d`#6_+u4vGCSA`e&Tw8W{*Q--_c2uu@-PTQ;TG~}Fc9HEJp<}ng`Sgbn8hMtT~+z|^=G&;;xnRgXj=|v z!!_XZ3?CCLOI^$^UoH;*ozQ?O0>|NnP5{4<;aO(AjWpCan8AalS>7({Qq3^f1QtRq zQyL}gc~8Z*63IN(H2-yYsK&cS4_{FoYCK~5-0<4QIgD~)XJb=XR{*{D+O=v)E)!r1 z<4ttp1(-f&hQ-avNzL(AW?Q>L=f=nm5L z<{m$P-jSyjt`@c}z7?FJUy!58%EpyS?4#cnBy+9Q(ECwbm}Y)HmoCS-!rDK-hz4oP zyu=3YuRc)xz-ED)eYu6CRGuZ8-C*G&E(*WFjxD>faTSVLEaI4Nw>=IFB%ZzdlcZ^X z_Ux$j)boB>x2pJ&YK_C7ee{3+9U+>>YkE9uev?MYp!SWcB-=y(y;m$AyV>RL?YQ7r zU`q6ZheepaKJ7NL3y>s}UQiccK88aA1UKxKzCPpS8DqZDa{6;7Qrz^cA{fl0pHnR< zA}%cK4M`lP3V09seg%aY<2@%1_(O;aEZ5EQC%Q3pr!=rwOkQvr(>aj>*qs6b3Y2$; zQ<51+HV&780oaL3h^s}x0UDbzv$G^hn0C)&5dbo{u;&`iOYk>MVaN!&6vFYXfJkgP z+_|1n+NKyZnSq`OV!!w7XTka33j6}ht$_80HW_~1Mir0q451coTQ!pE#Bl&f$Rs5< zLH7W{+_&D!IKtrU)s=Di^v;r%kj~Q|?D5wFa6%3m-GG=^L`rYluy2$ zz83FfnwJWC*(ZS4q@b$F0|KT(BQw+1^To+GV-9u2u0X=M1F@IycsO|V1Z;|6^%aTd% z{_l4qiwT*pAHAu_vbH+m?hN717?qpkzP}}1oE^KMzQlvMweD}=g(^6|(qdas_u!z4 z@(5UPpiYi6lI@o@ z@2e^0XuN-nor#aV`~|#We&@Vy(t?dUI~}X!lAk?%xDYxxy|rl_^7Rahijn>47axae z-ktlJp4#|4l5y8AvBl_+V>jC;5f{DSNL0znMGw+{_S2_rqwa(e6e~o7Zw0qa;&>Xk zr&-k|LkUW>Hc-FV7;f_cJ>*at8BGn1FtMM9$ssO4<6QXkw;QsUcoU3|3?R3d?yz10 zy8GB1{hvPRQw^Vb%)Xf#^(KCNu#Ed!M|bknv6%J#&z~`l8GBOu%bl|M_E9~4CShWS zu6AzFm34Z4ova~jdJ!Q`Ij`)&gW9&Xy$T9T;HZpCiF`#_jsprEspD~{fsxmH?L-Hu zHTeWPM435h{=~s)=dn$aN_U1))!Imd6ag9tBh|O^r&! zuitw2-7Vc|M7H^3H&A!tAcQ6*3?=O8?jEH&HxD*7uqe1xBfT7>P>)~&ZVl9wAtA1DUe5RnO^N*>}MAbP^!?SLl0Si&F`+uT#UT zlp?ST5kFH*X%w!dXNhNpjCXc?eBZh#J`sKeNey(9ZNo&4S|k;^+UQN-DIC1E_`Im- zcfZ$kGluwhdw8Ig@U>c7_vF!B^!h4^ zBTu|)34Be;{kN*-Z6Ct&7ug2sVOr=Xf!hHvK5^m%YU-UP&r9IJfBw6qi_IIITDE3UlI6TGbxWsZR^nlzReg4YRbVWFnA(<&|Fkxd$0`!Sn z`+-4vy2lm4_kc!y{S%$6SeC#zW=lhHc3;(h2m{UlFZRf9UkD*m(x;~A>F8h-ADkl| z$|wcQ67LZq3N=JJhD8bFWRzo>;=83x^GA>nqQTO8%)9d-n9<`+hzYzk0zgD!zg z2u&kEt)@^T;T}^@ab)AhP%|2+rXvlD2K@$p3t+LKcLysN(1AH#J^BBr6XK+^pi|tl zC#cc(`;Q-;{U5l)nYg$tz$O^FHg~LFHGtzMKOrD3%>uN@cwqyKtP*MZqV@gcsz80q zQi{{pA1kD4w=P zPv_pf$2mD)zkbaFiT&nUE>b{@7|1Uvnf$&b4m>RRZaiMD*+m#^CG`(0Fg)6IjSZ`{>nGoc-u)26sQx z)JsEYNmc`q4d%gsZ!L5vb6#>#&znhFI&l~$AJ7Hd2o95lkD9f`Z2!pxpi^(*MQQ>% z8U6|x1*S@+0c(Y2F;p>N3u00)D%GFwKe-TjUSPB|nX$!>G z&xhUq7bC9GZMw2^s;YljXNzNUJK@b>$KS_}F-{@X_+~^MU&P2f+%@x!3~(|87#yz^Tc%Eh9OqN1(L@y?TSD z{K6r1}KG>0U8)IGWc)hE(}vX`$0!*J@PLfbGU_MlC@6|WQ1aJ^VIi#H|@w{ zW9HyUiH$vLYby(?z^5W5Hp%t+qSDd;!Hd72jgKt^?9_bvf`W83+JAnY&rrnh6#0)I zY7f*rWuIHoSxCMr2mCv~ejqqRU2FUL;;!|Tt{S6?pVQ|+Au0Ui!XNu>Vj@^hG8@yq zBLh0k;g6p_sCe@jh0n^bY;^kWq{l|`QX;R9`-XHHuAaEybpM9Y6y!-uQqPO^;_xcql2Ti}cxbVDz zbHcsfBIOqYj8y-XYKLohdV7Dhq>!?BCH+bCBLF-g0N|;Jv$n&vwRqQML_TZ)sKspp z3-DJUSj128`}q3mH{}~K?cA9d9`?R!CyCc{*tEzzRYryg<6)4{h;wRd|ANL*Q$@bH zc_(SRm@$DMr$83HZ3ngT4cc`x3TNk$Ifl*6fMzoK?NU}XV~qjMA);dNJ9IC{gEKWH z`0uAZa9|zGvUfKF-(!TLN}di+6NK%;V=-0NS9(r-3)?xtA4MImF?M=&)UzDP7Ha+G zpL_GCg8|SXD&RqiC#3i;jNK|NU1T5r`d>+Yku|Ds$`!jETFnl;-9~V<4%$xTRXg{| z(=O8m#>D1l&+-ZRwM=?K@_-sjdO$TkN&o;p)}k*)ynsLe3l?z+2~BnZT=MdF%LX$a zJm?-6Q1<%xgi-qWt8$;gSftcaRm-I2zSIm1<0W6ek`YdwA_zV48zE?DsGZ?_=al&p zPUHm4i8suh|0M{AbvG%lgXG`8tK|em(hO8=mzO6HOr4|_E%RR7sy)oOY|-928tczX z<8&d?%%u!6>MT zLy0xgtP-S~ryZH8uFNbS2~CoMMf>hU!NLZ-ayw2M)wWRX*m-vIy3b$gp96uG6;?~v zH@SXH!=YYV08_{Hm29u>dzo!G!5?-TivSl)MEeJ^i8yGHg{O32nG(R6s1$7b@#B0) z86>!83rq=W0?cOW4T46wr>JlB3=T#gAjg@4AdMs!$==baqOBi}?Zf4dpJ$0zIB(pz zAfZAb*8FKsvVzm{fckpmRGL}WUL`hh)`7>KfA@)ZI&pDM5CXWU+@@b*a9Q-5yO9p6 zH~L@yJ$H@ZllEyh3roG5@|@`iVJ!d=7rzGE2xvQa&)RDG+T!pDl{`}{a^Qg3i4z`` zD^j2rpvPHMSjZo%-OpLrZ=ZnT16y%wWQ4a#hRKMAn|pbThCsM>jS%29J*2FeRU5m< zZTFAqpsLO3af3s#$$^xj`(FO)Y|%`<4Ev%|A88C(aYJZ9W{~r+io(Y@VTh7I;Y`s@daJ8DIAvzhXE|nG^Ku0>`)SP=1jB@( zSMQFn5!!y=t2ndjC`wZm+QE;$xmk>lFEIOGGaxxY>qMnrsJr6p$G$` zG+0#uyGK%z-duTpX^E{Oss}8to_fF^W277R^jL1s4+AHxQD+!@-?`DhFqW7X#Of8D z$oi^k=+l@A4Z&)c-W&O3(i#^siol%zNh#cZYkbO4MI|r!;8C5Zj9Ot$*D0F)4eM9! zb|d!%@BrWq7s#h(+ERDaAHZ-nDIo#RKFso{D2_iE$Fxs|+`6SNOyU3mhQyu70QSf| zN^WbeC5-b71e?;pI^pW8BsC9s2C~m4Js+8zgy@)!hbJ#5NBGh8x`&#P@M1!?J~=Vb zAeQwWlQn)09AFMFhWAGSZP*>A9XrHnsQYw%PO@Hz5Ix2l`~a#|3mL1Mhp&V=*W^BN z(=;~Ok+SZyI{Jc%Ipfq7v{8VjU?TCGkftwer;t2gRGquKG|mu>uxB&+unfnidHwpJ z|H8DWKAe{1j3YF71q`5YM4CSTCCf;tohR^){qq+uh&em_vN4uzltYjds?M&IeL0{o z5a2>h*h0x8%>1*rGye)Vb9e)zB->})jYlB43(tn_T_=(Zh6Sh{pq8JkH|Xf=-VD}bVM z$&BtVM=8nG2^0K!M~1#^C^)A|UqXscMNQq-+Iqn2$0-bxVQ)MHi)J*KNy*4U+eQBV zEv0y2&R;ik_(HmdBF&z~GusHB7*f-)>)lZ@Qob8$>FKbDf@T}qaQQPlXbJ!>fMW-+ zCX`dUJ<71iB_q1`?6gHyNGc85ukkJw04&RnYVa+mHD?>fjxOw~9o2&qpS`)YPzI3r(RU zw_WWW9DMQg>A{yqSVC%g2Z8Ybo5$lqRmJ9`gMQfI!w+D)UTYJjK$fB>WErl@dLQ3N zy0D%24cer86JJ9H1<(#e$2Zy8x3)x)pTR8{#5xa6fl4Qr(n7hc?k7^IXGliw4{u)G zvq^v31^@0;t=>32@*vr|W1`-n2%Va>LGNML&&9_+m+~_927;Qm>v`K(A2kj-%HRoU zB>emKRY1rBl+MtQF|Yq8+&$1r`F{B-v=*3iaf{=}&<2Ea5=JaRPrfZP(9aGOiD?)e zp(BtQ`zjsyJmRjn85+M7Aw)$Q2)Y*13h3S+xzdoza1#Z!l=KQ`KvorqM!glWQw)W` z^1Q#jAF?nH#Q~iCXeEMqsltW1?b#Wf_c#8&X?TQ#>;O6YnR`D-85-9~1?o^{k=S6o zU5`9@VDc{z(HHvin!z_D<)eTG5yirB^wjF>amy&h4Gj%}0YE?s0hzag-%PK+;+3ak z9(06v-`@=W$te1o2jl-6RC9SX^@D4w>F<;Fam;}2Yh-i@74E;k!J^{ITa>TCEU-Nz z<=YQaa5iyM40zwdgItK)4Xu>9d2_$;jX#^y>iR!^>|HVQfJFuWF3F;hkD*(mx#Po? zACl|p;yxWr0f~{-WU`eCv!G$|I<)ZE!yxU^t4Do~FPJkDWLgyG7f7fKB9i$qQr)F9 z?ZCsta4q8J(ucVr#sR^o!hbxnNvPEv27bVgEG)RX6NmHtIlCKvf6D3}dOl~k?Q$>Ca(UeUc+Oz^jZ>TCTJmp_ zGSj+D@O#aW7h`VAXYGsD1tjvI>HTV zYNF$UGAVIEJnA5h;)b!QoV>gh3itecX#j)OnLa*cQ%2gE=p&D@)&RRt2)bR$N)RtD;i_lW zn}}6^V2XWaW>)ZN1`ISg|5V@|Z8t%Sx4|B+!9SNi)zD^v|e@$i%lk z0+>G2U)y<4C;M{mH6KTnYeR}-%Wy5mDxFdhV59`s7LYiqaU`oSR$T|PT4-@^Gtv0~ zgSL@*H#nqGmM4}AovoX4bhztCJ<~OxYXWGFCmFp)hP0W|Lj7-}) zMcXc*#S)T(Q`Ud|l-e(KAzy}tN6_xu>_EOMZ7K8|B)F`+*}fAD6D<@ify@D&7pg9nP;W zGpc=aa z8F&?YJO?!;fZ1(UXW!(ZFg#tj7y{mZS;Y0*_=zVhh# z%czfEf4{gNDjX`zCP1dvltue|A@q%^#$e>$XJV0+yQl~h2GlRbH3occ>K=fK0;8;Bw6+2FbAtp`m#RScv?2JT$q`3vYl0b+n8*2u_c`4WyBU}Q)#8g~co zmnVu_d@@bRk$$&0eTo^Upm8B5$fu^?zkfe14XiI1)yRmp79b*$@;M`stjj!&uazOK zvr~T zKx1O|`(*ySs*a5$7zCM_yqI|Q1JxNKLJHWg(t*)EH*0Os{6CAlhSau(vZ0uyk+^wI zFqtf7Ibp>DP%Oig5IrF%3ek|zZj54r3>(g5v@|s1!yMt!(V7L6Vc*G#L69+v|K*HU zcc!5T9tfevp$HTaSW-%3nk9(yfJ-FerQv#`a_vqWiS50hf9}py@8n`uOF~l8xzkth zQ}KEQ^G-)m2;XME9)K_Cr7e!YGi*{%{u~q60C1qKjhcY71i`q;wg4UQ61dfDQf&Rx z!FqkUwYK&wN{e_EHc~#Ce->5ctz&O*?BD=10~Z0d4X2`4Dh6J~fd<-bE$XL%E^8CX0}K^TyrVT?bs_`m? zt&;nggX%9Rf4P$)p{z`jw2a_}!wuAbga8yMfNM1pGC)kmeH*&-+itsw8i91-3XzOF zTqOYs9TT9+8fG3q_VDh&$wX3vTC=m0K87dMj*B%dj7pxDaUb13r&`&b!I|c8G#^Ih z=3=_la^Cr&5NLY4XD~qxa2Uo57TW^j~_T}p`U(W zh*D_3oZRxYhs3WXRua6y8h!9#04Rsnev?%@*fY+~-!ZC&0Gc|6*aH=T9u6wBW4y7< zC>8(x9!>co9^o*ssL=m-gGtUta}DSF&*x-V&JicL`2 z`ReQF60d?_Va*m!;t9Ywu15TR8y|Pz9uqGl378`4b^W?>WFv%Ea8YV%a+q<_l2PYn z6tJF;Q|HsZsuMgDNPPS<^p7nTv!p3m(wzQ5$wP?qiU1db?=iy%L$=aVqCrLQ3(8<} zVlf!VzTHS+%|j0K1r}!Jrk!cpLh-Oq#Z?fBdIHp_Hl$x~-!`5>a~O<+ox)o~TeW10 zK8&}ygMMDD8Lj!qCTSgV;F8+uoqNS<-!X1F?y-H!jP@(<%?=xBv;pCbMeab%>jT+& zdU@Akw?9q;Ry7n(tDe;@9RtAqENKUJJqFB;E@g}Ch(Hzy5yhQuS{M0LHJ`PUTVss` z!q1=Yh8YqQ-PaY9Q)=S`2?SuPw&A}#84E)KJU`;ypl$KbqqmE7j)&)4TR8G*TF$;;DM<0>Z*3?2p^Y84}`rPWS0FKWLkFh48})QWh&nVA8tcBGip>*nGD4YaPF z9-L>AG4sf9B?fBLLxD4mbjW8;I27(m08Gz;*x*LRu*&k0YxFz=(@< z7Ui|fKY|=$rzKn0pHu|;8VL#T;R*9gp_R($Y7jEZIh^E13{=W}S+4s9>iGFd`ybk| zGy34;o1`8-A9TR~M`i){9~c(8?8M++B&B;|&Yt|=Ja+zBq7S7ti+D6Ck0($A7q7eA z-nE_Zyz@B1Yn8$l)91 ztIc0~oBO8U!GmB1z5hTWcI5DX@uYE*>!!Ptl(e+C*mN7cdaN*70!~K29S<2ImiPQu zTbc=h(cD<#S)p+j);*p5g`IqSc?>=zkH3_W;bg7LxgT)}Tu5*Uu%po6C3do$P8=3T z^{##4hsS$;fOeEO@@KT1%@?k`vbYG7Ky>dQTY{8p6K@qtMc7Bd?}JzmW01-h{@`!_ zL~TBPBmT7$k8iSQX61yMnTdY?Qa$kOo?7t6T&-kYp zBSFQ5tuGZHGatXa!Z5N$&KIE08yrbOw|B?WfSVK=JDl7NZ40g%GQFUb2>Z+Z?61lj zeS@6zA7A<|4Mkizc>39sOiId}#CDqkPNqmUM$H|;Z6v1*Ya_ND7S#4U)IiGbsb9$A zcY}w^Z01dduyeDr*)_}6((5ZRC%;$AalP*{*uUMl91rsK>#46_@2gz90ui{2Je}n< z^Ij%Oz9TtrpYd4VYYoRoeO>kRT~`+hJ5dNu1Oyr&hx&fGMeW34ElLj7$sbyei@tq_ zYZ`*6KZUUHd5PUIM7o(U4rg6}1{~&?B z49@}2i3dkQlaFg8t*`&?0#zS#p*Qfz_H*6aEyt)HqWR2NRaWVLly%+VRQ7%RMoDDP zl!THLB2UTQRE`lsc@RoTky&IELJ?9{**P4E@8|Yj?_aO0 z|GFIK9>4GWj6GO=79phkZr2?7cP81(nY0=V1Wy3A9B!i zLPa@F5`TFAx`SHo4P*Kjw9N;D%k{oFqw9cGIv|P2!^+7Wl|bZDb-Pf)>8~WO?sCcI zBz~x8l3;cZF4c(TA#7uF^Ue&ma}wlDl|@zz1^KS6IX{EnFP%m^f$9pXI$bdd!xk~x zY!;ktr6CyA452oMN-{*El-H&dCLmw~(}0;X)YMwPee!D!rN-#+%PssuOl>9wzVBm<@-XQW zWRJv{p|o@gTjm>IfKJo$8ig2Dobe{-U3yIb7UGz)yvE5x6I;m8*klVyNWZpn4+|H-8W#OVMDKAcOMG&_xdotf!?c@nnukd|z8{uc{u zx3=_ry=GOCQHfbMS=)`H_j({EmaZvQmQ(NCaLIml))50d_#0yMq*(&V;bm*D$Az`8 z?p0Lyzsx+BoXqMzv1HH`cNj&CH|Hv`?aTL>YQG@D$ES45lxmh00-GANsSqH5b_y!; zLK!uRS3m%yd@yk{Z~3Fd!a}R5q0aef1`p^3XSBKkKuQ{Mhm-;Y2LXB$2-V?4St_BT zPcMoKGYHOUXKXL_CP{ae?2FCD>5QJ(YNKU(bJrJ-@%LGa z4_`P>a^~PZ)O-fKPPT8-F$;-`1Rs^=k6RyhDeWD+Ip4X;01hT3~S14 zxAU-d3*=`L;^)I2su<@xmF)=Hb-?n7+o}!Rf`a!dqf%1RCAl-anFq6*Y^bIg>DR6) zoq4POU~~Q#AT$cnT2^T+pAdR`x%f8s)0?hxUtm1T`F`K6(^0#V=kz0MIyEP;pN|Q8 zsWDftY6gD)ghL1z2c*KRHt1G)IDarv4~)3X?lHn;WF(W-qO7dF?&|fTyLTT{R!$9j zV{3vzce^+_I1##X!*chpR81}Cr_spD8uXm*blIm?l%|g}YO0rJWo}~ufpn9f573d8 zni?5~#Gd{AJsYQ7i1`9Zd?@nHc3f~g2uvX4F;sx{DZ=xIRE6{#h50hI4h|0EeTnrCq!oJSG zZrj$aCx9IrIvk;!!yeB^hh_i?;l9Ux%#9)>!ghgpQyKo!NShcObUF~~LB7pVt#dv8)^XjG6v9$N%Y4@7xd zaoYFq-}zv)K~9Kh7jMvVV@x`Z{>y>8Hp{f z8IF0V@i;g*V822(d!F0@bG5&+lvYwG&qJz3`=KBZJmfbaKs5_xc;>(Qfrk;|c&H9S zeXZCrWogv`aHi{@c~nr~BQEO+yA`_;T`(@?_XoTlG(>4MLkgEv?FPL=!6d0_?EgBA412 zKDRGLf?Ei{gyGfCCtXWW`6BU3Na)B2ToqH>wPz0$txn@fp~1&k4hU){YToVF59S`mZ2W%L^x^*dEM(Rd@U&HJWWSXaAd|tKjSMJ`e|Hu+%8~a4}MH&lH z>DlmFB)C}pOVIZ4)*hP{p*|=8ND*97?+`9g@Sy(r7-fhT44Yp915q#+)`eNgzW1&g zDm^zpokOQDjI|_1W$_UR>o`|1^uV(Ll()0Y)x47XuJk1KakRdGd9-Xm2m1K>!t@VN zG;1LL006LppENX8%LdT00+&*r%oih@S_|#TRegTK`8Qj+g8RgM;bz@^0ld8zM

$4(? z>oH-+sK)crzpP;x17%L#AtoC;-0w4?|9(>!S_j?R+CN~25L--diCAqxT1+wCG*mhN z0`G;VCnzPTXC`OGz6!P(;F=?G13>zG;#{6{_A85nMAT=+gXd!?d+zx?4y}uN>q7Uf zf1fulbUU>E_8VbpS3kX3Ej=Q3G3)LGJ62FfgFAMcnF$C7v|+ZcZ6%;DX>yZwRa8No zy}Z3Wc${|S9o-Sx8?CH$avncROx>Y#N@3I!-5+TUF!xdxz~I^~OtIoxcz<)63&(QB?&wn}HQ$2Z~SBh|&bswx=8MDHzJ^O(m%lx5XEukxLawrbbdi494yZe9( zhZokIq)!ISR8WD@Ya8gfWCp4Bsv2DS^>t)&da&f1_2wN6#*+M#xl^_r3?;Ftpm(93 zv#%n1Y`c?>+z++6^71g@#ZVb|LuhBQ%U74!4^qOFa9R7Z@p;m zb~VItOf)`*8gcsYKOg6fj#7H}+9i!cdS?p}KJ;&rAxb%S*QW9??*qdtR}%v7-^S~` z{=qxX{O1hYthG#AbA6lbf(E-1F*;Uyc95NDzGjiYG*a1lURcn;Ea-R@_uhR|iHGt< zXqOev=r2f{q)tOupX<*rsQ#AO7T2DCcBO-?DWwJtR2JvPO4iOWjV5UjPLss$x`Hpw zHEoORYmA&!h}aEtFG@E&AkM0KcZ?tW>ua~3#HuT`KRywtuKlBOj$yHP^2`jhYpi%>1NKwkbGte_x%OnaL8|eZbBRWhb=yc#v48S*87VHtE&3>dur)+FHZv+$J^@PCVKA< zf0!)fzk&RqD}wPH=yNRcf(Ft1baF4naRQf=U*| zhIv2Lm#_@w)mz&be7>@?^!b3Ey?K*NWl#{@nZY%#TOPVvB4P&( z=j&+SpSo--+O90$qzF*Me1mZ4yLrObYZeb+|>@@GI|7WFlapUiR1( z1bZa>S70tKK$ndLRVEZ_$vgk2?03DX{{D_|R$Vp;QNO8S`uzM^*mLV-bWfAy6rX^A ztX-$lKj{L`dqAIMU zVuhaSpOob-@OQeUQHDlP#WI1wcvJ4eJwHATPRWSl3W>&~dYP|~YX>_A2Lvzv+la@- zadwR-NGzXuk`Iefd}(1JW`W04g_~}vBnD17q+JU4_f3ts6r%jPX3YB>@&k|^+S+00 z3RU@}()IC7^zR_3LLfxz>@*Ev)@s4{7K$=$K{wAXqIV2hlYkBjHh^Q;FUF zQffk*{Jl5y+1|r|=)!78;7a3p&8%@>W8o@$2Xk|nYoCIfGgbjz#k_thsKb!q25}XciJIiBt;3`_Pn_v$PbU()FKkNbojkeY;=V#Z9&Jc@zel36vd;$-PJ`ghpyfXViyXpQq9xqRU(N;&W?04$4a@rmvI!w@}|Om&MOW>S&w{d*Mq z(6Zy?;IIr*XWk?&&HNeJ~&*Fi?g0Mr-Ry1atS*dJY>UB`?zc zd#_S~4V^jpHUGc~3@%}3MY?hMj@Uy`zvaF6uA4*e%%EY=ev$-z$HuCvxt8~96vZLD zL6I?Fv9PpM%e`Ahu(kwyIcR+xP3q=ceoAiyYnibK*{E;HkOq`e)Ac#j~L!_M2r3mKc3X??NF*IeaFHLop}lSgzwWcvcONLqyK*0j zY%vXMeA1aGqYy>gDs9%Z@LR=yO@_-THp3a|LoxZEG>0Pb4U%Kx z<6T_?8bkl&JzSc6wm*(c#t}TPIMT0Zvq>DHNbi)BNiAk%$HkRCKW%lJdx<-c_9m?0 S;1@>%KYI;K^-FY}F8&92)>HKW From 80f3d4eb4c2b2af8bfc195fcc0b1459d82a31e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Peris?= Date: Tue, 25 Apr 2017 09:04:14 +0200 Subject: [PATCH 11/25] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3249ae8..702cae5 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,8 @@ NMT-Keras requires the following libraries: ### Decoding - We can translate new text using the [sample_ensemble.py](https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py) script. Please, refer to the [ensembling_tutorial](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md) for more details of this script. -In short, if we want to use the models from the first three epochs on the val split, just run: + Once we have our model trained, we can translate new text using the [sample_ensemble.py](https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py) script. Please refer to the [ensembling_tutorial](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md) for more details about this script. +In short, if we want to use the models from the first three epochs to translate the `examples/EuTrans/test.en` file, just run: ```bash python sample_ensemble.py --models trained_models/tutorial_model/epoch_1 \ From 46027fc6fec988cbb65c267f83581c0f22d50cca Mon Sep 17 00:00:00 2001 From: lvapeab Date: Tue, 25 Apr 2017 13:49:28 +0200 Subject: [PATCH 12/25] Docs --- docs/Makefile | 225 +++++++++++++++++++++++++++++++ docs/conf.py | 350 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 22 ++++ 3 files changed, 597 insertions(+) create mode 100644 docs/Makefile create mode 100644 docs/conf.py create mode 100644 docs/index.rst diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..ee5ce09 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,225 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/NMT-Keras.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/NMT-Keras.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/NMT-Keras" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/NMT-Keras" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..7b85c2b --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,350 @@ +# -*- coding: utf-8 -*- +# +# NMT-Keras documentation build configuration file, created by +# sphinx-quickstart on Tue Apr 25 13:48:51 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'NMT-Keras' +copyright = u'2017, Álvaro Peris' +author = u'Álvaro Peris' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = u'0.1' +# The full version, including alpha/beta/rc tags. +release = u'0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = u'NMT-Keras v0.1' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +# html_logo = None + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +# +# html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +# +# html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +htmlhelp_basename = 'NMT-Kerasdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'NMT-Keras.tex', u'NMT-Keras Documentation', + u'Álvaro Peris', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +# +# latex_use_parts = False + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# It false, will not define \strong, \code, itleref, \crossref ... but only +# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added +# packages. +# +# latex_keep_old_macro_names = True + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'nmt-keras', u'NMT-Keras Documentation', + [author], 1) +] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'NMT-Keras', u'NMT-Keras Documentation', + author, 'NMT-Keras', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..2e400f1 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,22 @@ +.. NMT-Keras documentation master file, created by + sphinx-quickstart on Tue Apr 25 13:48:51 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to NMT-Keras's documentation! +===================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + From 049eec55678fe6304d87e0cc43080640ed8eeace Mon Sep 17 00:00:00 2001 From: lvapeab Date: Tue, 25 Apr 2017 18:12:26 +0200 Subject: [PATCH 13/25] First docs version --- .gitignore | 2 +- docs/Makefile | 6 ++-- docs/index.rst | 22 ------------- docs/{ => source}/conf.py | 37 +++++++++++----------- docs/source/help.rst | 22 +++++++++++++ docs/source/index.rst | 43 ++++++++++++++++++++++++++ docs/source/requirements.rst | 11 +++++++ docs/source/resources.rst | 23 ++++++++++++++ docs/source/usage.rst | 60 ++++++++++++++++++++++++++++++++++++ 9 files changed, 182 insertions(+), 44 deletions(-) delete mode 100644 docs/index.rst rename docs/{ => source}/conf.py (93%) create mode 100644 docs/source/help.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/requirements.rst create mode 100644 docs/source/resources.rst create mode 100644 docs/source/usage.rst diff --git a/.gitignore b/.gitignore index 72364f9..8bbd663 100644 --- a/.gitignore +++ b/.gitignore @@ -61,7 +61,7 @@ instance/ .scrapy # Sphinx documentation -docs/_build/ +#docs/_build/ # PyBuilder target/ diff --git a/docs/Makefile b/docs/Makefile index ee5ce09..ca5a939 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -5,14 +5,14 @@ SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = -BUILDDIR = _build +BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help help: diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 2e400f1..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. NMT-Keras documentation master file, created by - sphinx-quickstart on Tue Apr 25 13:48:51 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to NMT-Keras's documentation! -===================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/docs/conf.py b/docs/source/conf.py similarity index 93% rename from docs/conf.py rename to docs/source/conf.py index 7b85c2b..169b459 100644 --- a/docs/conf.py +++ b/docs/source/conf.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # NMT-Keras documentation build configuration file, created by -# sphinx-quickstart on Tue Apr 25 13:48:51 2017. +# sphinx-quickstart on Tue Apr 25 15:21:41 2017. # # This file is execfile()d with the current directory set to its # containing dir. @@ -25,22 +25,18 @@ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' - +import guzzle_sphinx_theme # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', 'sphinx.ext.mathjax', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', ] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ['ntemplates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: @@ -65,9 +61,9 @@ # built documents. # # The short X.Y version. -version = u'0.1' +version = u'0.0.1' # The full version, including alpha/beta/rc tags. -release = u'0.1' +release = u'0.0.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -88,7 +84,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -119,7 +115,7 @@ # keep_warnings = False # If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True +todo_include_todos = False # -- Options for HTML output ---------------------------------------------- @@ -127,8 +123,17 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme_path = guzzle_sphinx_theme.html_theme_path() +html_theme = 'guzzle_sphinx_theme' + +# Register the theme as an extension to generate a sitemap.xml +extensions.append("guzzle_sphinx_theme") +# Guzzle theme options (see theme.conf for more information) +html_theme_options = { + # Set the name of the project to appear in the sidebar + "project_nav_name": "NMT-Keras", +} # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. @@ -141,7 +146,7 @@ # The name for this set of Sphinx documents. # " v documentation" by default. # -# html_title = u'NMT-Keras v0.1' +# html_title = u'NMT-Keras v0.0.1' # A shorter title for the navigation bar. Default is the same as html_title. # @@ -161,7 +166,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ['nstatic'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied @@ -344,7 +349,3 @@ # If true, do not generate a @detailmenu in the "Top" node's menu. # # texinfo_no_detailmenu = False - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://docs.python.org/': None} diff --git a/docs/source/help.rst b/docs/source/help.rst new file mode 100644 index 0000000..13a757d --- /dev/null +++ b/docs/source/help.rst @@ -0,0 +1,22 @@ +Help +==== + +If you have any trouble using NMT-Keras, please drop an email to: lvapeab@prhlt.upv.es + +Acknowledgement +^^^^^^^^^^^^^^^ + +Much of this library has been developed together with `Marc Bolaños`_ for other sequence-to-sequence problems. + +To see other projects following the philosophy of NMT-Keras, take a look to: + +* TMA_: for egocentric captioning based on temporally-linked sequences. +* VIBIKNet_: for visual question answering. +* ABiViRNet_: for video description. +* `Sentence SelectioNN`_ for sentence classification and selection. + +.. _Marc Bolaños: https://github.com/MarcBS +.. _TMA: https://github.com/MarcBS/TMA +.. _VIBIKNet: https://github.com/MarcBS/VIBIKNet +.. _ABiViRNet: https://github.com/lvapeab/ABiViRNet +.. _Sentence SelectioNN: https://github.com/lvapeab/sentence-selectioNN \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000..769463d --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,43 @@ +NMT-Keras +========= + +Neural Machine Translation with Keras (+ Theano backend). + +Features +======== + + * Attention model over the input sequence of annotations. + * Peeked decoder: The previously generated word is an input of the current timestep. + * Beam search decoding. + * Ensemble decoding. + * Support for GRU/LSTM networks. + * Multilayered residual GRU/LSTM networks. + * N-best list generation (as byproduct of the beam search process). + * Unknown words replacement. + * Use of pretrained (Glove_ or Word2Vec_) word embedding vectors. + * MLPs for initializing the RNN hidden and memory state. + * Spearmint_ wrapper for hyperparameter optimization. + +.. _Spearmint: https://github.com/HIPS/Spearmint +.. _Glove: http://nlp.stanford.edu/projects/glove/ +.. _Word2Vec: https://code.google.com/archive/p/word2vec/ + + + +Guide +***** +.. toctree:: + :maxdepth: 3 + + requirements + usage + resources + help + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/source/requirements.rst b/docs/source/requirements.rst new file mode 100644 index 0000000..425d483 --- /dev/null +++ b/docs/source/requirements.rst @@ -0,0 +1,11 @@ +Requirements +============ + - Our version of Keras_. + - `Multimodal Keras Wrapper`_.::. See the documentation_ and tutorial_. + - Coco-caption_ evaluation package (Only required to perform evaluation). + +.. _Keras: https://github.com/MarcBS/keras +.. _Multimodal Keras Wrapper: https://github.com/lvapeab/multimodal_keras_wrapper +.. _documentation: http://marcbs.github.io/staged_keras_wrapper/ +.. _tutorial: http://marcbs.github.io/multimodal_keras_wrapper/tutorial.html +.. _Coco-caption: https://github.com/lvapeab/coco-caption \ No newline at end of file diff --git a/docs/source/resources.rst b/docs/source/resources.rst new file mode 100644 index 0000000..bf345d8 --- /dev/null +++ b/docs/source/resources.rst @@ -0,0 +1,23 @@ +Resources +========= + +- Overview_ of an attentional NMT system. + +- NMT-Keras `step-by-step guide`_: Tutorials for running this library. They are expected to be followed in order: + + 1. `Dataset setup`_: Shows how to invoke and configure a Dataset instance for a translation problem. + 2. `Training tutorial`_: Shows how to call a translation model, link it with the dataset object and construct calllbacks for monitorizing the training. + 3. `Decoding tutorial`_: Shows how to call a trained translation model and use it to translate new text. + 4. `NMT model tutorial`_: Shows how to build a state-of-the-art NMT model with Keras in few (~50) lines. + +.. _Overview: https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/neural_machine_translation.pdf +.. _step-by-step guide: https://github.com/lvapeab/nmt-keras/blob/master/examples +.. _Dataset setup: https://github.com/lvapeab/nmt-keras/blob/master/examples/1_dataset_tutorial.ipynb +.. _Training tutorial: https://github.com/lvapeab/nmt-keras/blob/master/examples/2_training_tutorial.ipynb +.. _Decoding tutorial: https://github.com/lvapeab/nmt-keras/blob/master/examples/3_decoding_tutorial.ipynb +.. _NMT model tutorial: https://github.com/lvapeab/nmt-keras/blob/master/examples/4_nmt_model_tutorial.ipynb + + + + + diff --git a/docs/source/usage.rst b/docs/source/usage.rst new file mode 100644 index 0000000..ddf1378 --- /dev/null +++ b/docs/source/usage.rst @@ -0,0 +1,60 @@ +Usage +===== + +Training +******** + +1) Set a training configuration in the config.py_ script. Each parameter is commented. See the `documentation file`_ for further info about each specific hyperparameter. You can also specify the parameters when calling the `main.py`_ script following the syntax `Key=Value` +2) Train!: + + python main.py + + +Decoding +******** +Once we have our model trained, we can translate new text using the `sample_ensemble.py`_ script. Please refer to the `ensembling tutorial`_ for more details about this script. +In short, if we want to use the models from the first three epochs to translate the `examples/EuTrans/test.en` file, just run::: + + python sample_ensemble.py --models trained_models/tutorial_model/epoch_1 \ + trained_models/tutorial_model/epoch_2 \ + --dataset datasets/Dataset_tutorial_dataset.pkl \ + --text examples/EuTrans/test.en + +Scoring +******** + +The `score.py`_ script can be used to obtain the (-log)probabilities of a parallel corpus. Its syntax is the following::: + + python score.py --help + usage: Use several translation models for scoring source--target pairs + [-h] -ds DATASET [-src SOURCE] [-trg TARGET] [-s SPLITS [SPLITS ...]] + [-d DEST] [-v] [-c CONFIG] --models MODELS [MODELS ...] + optional arguments: + -h, --help show this help message and exit + -ds DATASET, --dataset DATASET + Dataset instance with data + -src SOURCE, --source SOURCE + Text file with source sentences + -trg TARGET, --target TARGET + Text file with target sentences + -s SPLITS [SPLITS ...], --splits SPLITS [SPLITS ...] + Splits to sample. Should be already included into the + dataset object. + -d DEST, --dest DEST File to save scores in + -v, --verbose Be verbose + -c CONFIG, --config CONFIG + Config pkl for loading the model configuration. If not + specified, hyperparameters are read from config.py + --models MODELS [MODELS ...] + path to the models + + + + +.. _documentation file: https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/config.md +.. _config.py: https://github.com/lvapeab/nmt-keras/blob/master/config.py +.. _main.py: https://github.com/lvapeab/nmt-keras/blob/master/main.py +.. _sample_ensemble.py: https://github.com/lvapeab/nmt-keras/blob/master/sample_ensemble.py +.. _ensembling tutorial: https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md +.. _score.py: https://github.com/lvapeab/nmt-keras/blob/master/score.py + From 9f1ed80c670580062b375a0f9612789baa63df77 Mon Sep 17 00:00:00 2001 From: lvapeab Date: Tue, 25 Apr 2017 18:15:53 +0200 Subject: [PATCH 14/25] Update docs conf.py --- docs/source/conf.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 169b459..55c679a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,7 @@ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' -import guzzle_sphinx_theme + # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. @@ -123,17 +123,8 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # +html_theme = 'alabaster' -html_theme_path = guzzle_sphinx_theme.html_theme_path() -html_theme = 'guzzle_sphinx_theme' - -# Register the theme as an extension to generate a sitemap.xml -extensions.append("guzzle_sphinx_theme") -# Guzzle theme options (see theme.conf for more information) -html_theme_options = { - # Set the name of the project to appear in the sidebar - "project_nav_name": "NMT-Keras", -} # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. From 2c53194628b81d1bbe7ed71fee9ac492cebb74d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Peris?= Date: Wed, 26 Apr 2017 13:04:19 +0200 Subject: [PATCH 15/25] Update README.md --- examples/README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/examples/README.md b/examples/README.md index 53beaa6..c1af017 100644 --- a/examples/README.md +++ b/examples/README.md @@ -26,11 +26,3 @@ In the `documentation` folder you'll find a couple of pdf files: * [staged_keras_wrapper.pdf](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/staged_keras_wrapper.pdf) contains the autogenerated documentation for the staged_keras_wrapper package (at 30/Nov/2016). * [typical_output.md](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/typical_output.md) describes the files and output generated during a typical training run. * [ensembling_tutorial.md](https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md) shows the usage of the `sample_ensemble` script. - -## TODO list - -- [x] Add a tutorial for building a NMT model with Keras. - -- [ ] Document (with sphinx) the NMT-Keras library - -- [x] Add a document explaining the typical output of a training. From 44e2e42fd6e61c0c45420cea01daa0d2f0bb17ac Mon Sep 17 00:00:00 2001 From: lvapeab Date: Wed, 26 Apr 2017 13:58:41 +0200 Subject: [PATCH 16/25] Update Tutorials --- examples/1_dataset_tutorial.ipynb | 154 +++++++++++++++++++++------- examples/2_training_tutorial.ipynb | 98 +++++++++++------- examples/4_nmt_model_tutorial.ipynb | 74 +++++-------- 3 files changed, 199 insertions(+), 127 deletions(-) diff --git a/examples/1_dataset_tutorial.ipynb b/examples/1_dataset_tutorial.ipynb index 967e00c..2cdec09 100644 --- a/examples/1_dataset_tutorial.ipynb +++ b/examples/1_dataset_tutorial.ipynb @@ -41,8 +41,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "Using Theano backend.\n", - "Using gpu device 0: GeForce GTX 1080 (CNMeM is disabled, cuDNN 5105)\n" + "Using Theano backend.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using cuDNN version 5105 on context None\nMapped name None to device cuda: GeForce GTX 1080 (0000:01:00.0)\n" ] } ], @@ -77,7 +83,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "collapsed": true }, @@ -86,16 +92,40 @@ "name": "stderr", "output_type": "stream", "text": [ - "[30/11/2016 18:30:49] Creating vocabulary for data with id 'target_text'.\n", - "[30/11/2016 18:30:49] \t Total: 513 unique words in 9900 sentences with a total of 98304 words.\n", - "[30/11/2016 18:30:49] Creating dictionary of 30000 most common words, covering 100.0% of the text.\n", - "[30/11/2016 18:30:49] Loaded \"train\" set outputs of type \"text\" with id \"target_text\" and length 9900.\n", - "[30/11/2016 18:30:49] Loaded \"val\" set outputs of type \"text\" with id \"target_text\" and length 100.\n" + "[26/04/2017 13:48:48] Creating vocabulary for data with id 'target_text'.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:48] \t Total: 513 unique words in 9900 sentences with a total of 98304 words.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:48] Creating dictionary of 30000 most common words, covering 100.0% of the text.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:48] Loaded \"train\" set outputs of type \"text\" with id \"target_text\" and length 9900.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:48] Loaded \"val\" set outputs of type \"text\" with id \"target_text\" and length 100.\n" ] } ], "source": [ - "ds.setOutput('examples/EuTrans/DATA/training.en',\n", + "ds.setOutput('examples/EuTrans/training.en',\n", " 'train',\n", " type='text',\n", " id='target_text',\n", @@ -107,7 +137,7 @@ " max_words=30000,\n", " min_occ=0)\n", "\n", - "ds.setOutput('examples/EuTrans/DATA//dev.en',\n", + "ds.setOutput('examples/EuTrans/dev.en',\n", " 'val',\n", " type='text',\n", " id='target_text',\n", @@ -128,7 +158,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "collapsed": true }, @@ -137,16 +167,40 @@ "name": "stderr", "output_type": "stream", "text": [ - "[30/11/2016 18:30:51] Creating vocabulary for data with id 'source_text'.\n", - "[30/11/2016 18:30:51] \t Total: 686 unique words in 9900 sentences with a total of 96172 words.\n", - "[30/11/2016 18:30:51] Creating dictionary of 30000 most common words, covering 100.0% of the text.\n", - "[30/11/2016 18:30:51] Loaded \"train\" set inputs of type \"text\" with id \"source_text\" and length 9900.\n", - "[30/11/2016 18:30:51] Loaded \"val\" set inputs of type \"text\" with id \"source_text\" and length 100.\n" + "[26/04/2017 13:48:52] Creating vocabulary for data with id 'source_text'.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:52] \t Total: 686 unique words in 9900 sentences with a total of 96172 words.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:52] Creating dictionary of 30000 most common words, covering 100.0% of the text.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:52] Loaded \"train\" set inputs of type \"text\" with id \"source_text\" and length 9900.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:52] Loaded \"val\" set inputs of type \"text\" with id \"source_text\" and length 100.\n" ] } ], "source": [ - "ds.setInput('examples/EuTrans/DATA//training.es',\n", + "ds.setInput('examples/EuTrans/training.es',\n", " 'train',\n", " type='text',\n", " id='source_text',\n", @@ -157,7 +211,7 @@ " max_text_len=30,\n", " max_words=30000,\n", " min_occ=0)\n", - "ds.setInput('examples/EuTrans/DATA//dev.es',\n", + "ds.setInput('examples/EuTrans/dev.es',\n", " 'val',\n", " type='text',\n", " id='source_text',\n", @@ -177,7 +231,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "collapsed": true }, @@ -186,14 +240,26 @@ "name": "stderr", "output_type": "stream", "text": [ - "[30/11/2016 18:30:52] \tReusing vocabulary named \"target_text\" for data with id \"state_below\".\n", - "[30/11/2016 18:30:52] Loaded \"train\" set inputs of type \"text\" with id \"state_below\" and length 9900.\n", - "[30/11/2016 18:30:52] Loaded \"val\" set inputs of type \"ghost\" with id \"state_below\" and length 100.\n" + "[26/04/2017 13:48:58] \tReusing vocabulary named \"target_text\" for data with id \"state_below\".\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:58] Loaded \"train\" set inputs of type \"text\" with id \"state_below\" and length 9900.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:58] Loaded \"val\" set inputs of type \"ghost\" with id \"state_below\" and length 100.\n" ] } ], "source": [ - "ds.setInput('examples/EuTrans/DATA//training.en',\n", + "ds.setInput('examples/EuTrans/training.en',\n", " 'train',\n", " type='text',\n", " id='state_below',\n", @@ -221,7 +287,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "collapsed": false }, @@ -230,8 +296,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "[30/11/2016 18:30:54] Keeping 1 captions per input on the val set.\n", - "[30/11/2016 18:30:54] Samples reduced to 100 in val set.\n" + "[26/04/2017 13:48:59] Keeping 1 captions per input on the val set.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:48:59] Samples reduced to 100 in val set.\n" ] } ], @@ -249,25 +321,29 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 7, "metadata": { "collapsed": true }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:49:01] <<< Saving Dataset instance to datasets/Dataset_tutorial_dataset.pkl ... >>>\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[26/04/2017 13:49:01] <<< Dataset instance saved >>>\n" + ] + } + ], "source": [ "saveDataset(ds, 'datasets')" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "" - ] } ], "metadata": { diff --git a/examples/2_training_tutorial.ipynb b/examples/2_training_tutorial.ipynb index e7066be..4b55077 100644 --- a/examples/2_training_tutorial.ipynb +++ b/examples/2_training_tutorial.ipynb @@ -36,21 +36,21 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "30/11/2016_16:33:14: <<< Loading Dataset instance from datasets/Dataset_tutorial_dataset.pkl ... >>>\n" + "[26/04/2017 13:51:24] <<< Loading Dataset instance from datasets/Dataset_tutorial_dataset.pkl ... >>>\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "30/11/2016_16:33:14: <<< Dataset instance loaded >>>\n" + "[26/04/2017 13:51:24] <<< Dataset instance loaded >>>\n" ] } ], @@ -60,6 +60,7 @@ "import utils\n", "from keras_wrapper.cnn_model import loadModel\n", "from keras_wrapper.dataset import loadDataset\n", + "from keras_wrapper.extra.callbacks import PrintPerformanceMetricOnEpochEndOrEachNUpdates\n", "params = load_parameters()\n", "dataset = loadDataset('datasets/Dataset_tutorial_dataset.pkl')" ] @@ -73,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": 52, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -90,62 +91,76 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "30/11/2016_16:33:18: <<< Building GroundHogModel Translation_Model >>>\n" + "[26/04/2017 13:50:11] <<< Building GroundHogModel Translation_Model >>>\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "-----------------------------------------------------------------------------------\n\t\tTranslationModel instance\n-----------------------------------------------------------------------------------\n_model_type: GroundHogModel\nname: tutorial_model\nmodel_path: trained_models/tutorial_model/\nverbose: True\n\nMODEL PARAMETERS:\n{'SOURCE_GLOVE_VECTORS': None, 'SAMPLE_ON_SETS': ['train', 'val'], 'CLIP_C': 1.0, 'HEURISTIC': 1, 'EVAL_EACH': 1, 'TRG_LAN': 'en', 'SAMPLING': 'max_likelihood', 'SAMPLE_EACH_UPDATES': 2500, 'N_LAYERS_DECODER': 1, 'POS_UNK': False, 'ENCODER_HIDDEN_SIZE': 600, 'REBUILD_DATASET': True, 'METRICS': ['coco'], 'OPTIMIZER': 'Adam', 'SOURCE_TEXT_EMBEDDING_SIZE': 420, 'EVAL_EACH_EPOCHS': True, 'EPOCHS_FOR_SAVE': 1, 'USE_BATCH_NORMALIZATION': True, 'BATCH_SIZE': 50, 'MODEL_NAME': 'ue_GroundHogModel_src_emb_420_bidir_True_enc_600_dec_600_deepout_maxout_trg_emb_420_Adam_0.001', 'BATCH_NORMALIZATION_MODE': 1, 'N_SAMPLES': 5, 'PARALLEL_LOADERS': 8, 'MIN_OCCURRENCES_VOCAB': 0, 'OUTPUTS_IDS_DATASET': ['target_text'], 'INIT_LAYERS': ['tanh'], 'EARLY_STOP': True, 'DATA_AUGMENTATION': False, 'TEXT_FILES': {'test': 'DATA/test.', 'train': 'DATA/training.', 'val': 'DATA/dev.'}, 'START_SAMPLING_ON_EPOCH': 1, 'SAMPLE_WEIGHTS': True, 'SAMPLING_SAVE_MODE': 'list', 'EXTRA_NAME': '', 'LOSS': 'categorical_crossentropy', 'WRITE_VALID_SAMPLES': True, 'INPUTS_IDS_MODEL': ['source_text', 'state_below'], 'MODE': 'training', 'LR_GAMMA': 0.8, 'NOISE_AMOUNT': 0.01, 'STOP_METRIC': 'Bleu_4', 'N_LAYERS_ENCODER': 1, 'WEIGHT_DECAY': 0.0001, 'BIDIRECTIONAL_ENCODER': True, 'MAX_OUTPUT_TEXT_LEN_TEST': 120, 'FORCE_RELOAD_VOCABULARY': False, 'layer': ('maxout', 210), 'TOKENIZATION_METHOD': 'tokenize_none', 'DEEP_OUTPUT_LAYERS': [('maxout', 210)], 'OUTPUT_VOCABULARY_SIZE': 516, 'START_EVAL_ON_EPOCH': 10, 'BEAM_SEARCH': True, 'TARGET_TEXT_EMBEDDING_SIZE': 420, 'DECODER_HIDDEN_SIZE': 600, 'MODEL_TYPE': 'GroundHogModel', 'MAX_INPUT_TEXT_LEN': 50, 'EVAL_ON_SETS_KERAS': [], 'NORMALIZE_SAMPLING': True, 'MAX_OUTPUT_TEXT_LEN': 50, 'PAD_ON_BATCH': True, 'USE_PRELU': False, 'INPUT_VOCABULARY_SIZE': 689, 'BEAM_SIZE': 12, 'TRAIN_ON_TRAINVAL': False, 'LR': 0.001, 'SRC_LAN': 'es', 'CLASSIFIER_ACTIVATION': 'softmax', 'FILL': 'end', 'ALPHA_FACTOR': 0.6, 'TEMPERATURE': 1, 'STORE_PATH': 'trained_models/ue_GroundHogModel_src_emb_420_bidir_True_enc_600_dec_600_deepout_maxout_trg_emb_420_Adam_0.001/', 'DATASET_STORE_PATH': 'datasets/', 'DROPOUT_P': 0.5, 'DATA_ROOT_PATH': '/media/HDD_2TB/DATASETS/ue/', 'HOMOGENEOUS_BATCHES': False, 'LR_DECAY': 20, 'DATASET_NAME': 'ue', 'USE_DROPOUT': False, 'INPUTS_IDS_DATASET': ['source_text', 'state_below'], 'VERBOSE': 1, 'PATIENCE': 20, 'OUTPUTS_IDS_MODEL': ['target_text'], 'USE_NOISE': True, 'TARGET_GLOVE_VECTORS': None, 'TARGET_GLOVE_VECTORS_TRAINABLE': True, 'RELOAD': 0, 'EVAL_ON_SETS': ['val'], 'MAX_EPOCH': 500, 'SOURCE_GLOVE_VECTORS_TRAINABLE': True, 'USE_L2': False}\n-----------------------------------------------------------------------------------\n____________________________________________________________________________________________________\nLayer (type) Output Shape Param # Connected to \n====================================================================================================\nsource_text (InputLayer) (None, None) 0 \n____________________________________________________________________________________________________\nsource_word_embedding (Embedding)(None, None, 420) 289380 source_text[0][0] \n____________________________________________________________________________________________________\nsrc_embedding_gaussian_noise (Gau(None, None, 420) 0 source_word_embedding[0][0] \n____________________________________________________________________________________________________\nsrc_embedding_batch_normalization(None, None, 420) 840 src_embedding_gaussian_noise[0][0\n____________________________________________________________________________________________________\nbidirectional_encoder (Bidirectio(None, None, 1200) 3675600 src_embedding_batch_normalization\n____________________________________________________________________________________________________\nannotations_gaussian_noise (Gauss(None, None, 1200) 0 bidirectional_encoder[0][0] \n____________________________________________________________________________________________________\nannotations_batch_normalization ((None, None, 1200) 2400 annotations_gaussian_noise[0][0] \n____________________________________________________________________________________________________\nstate_below (InputLayer) (None, None) 0 \n____________________________________________________________________________________________________\nmaskedmean_2 (MaskedMean) (None, 1200) 0 annotations_batch_normalization[0\n____________________________________________________________________________________________________\ntarget_word_embedding (Embedding)(None, None, 420) 216720 state_below[0][0] \n____________________________________________________________________________________________________\ninitial_state (Dense) (None, 600) 720600 maskedmean_2[0][0] \n____________________________________________________________________________________________________\nstate_below_gaussian_noise (Gauss(None, None, 420) 0 target_word_embedding[0][0] \n____________________________________________________________________________________________________\ninitial_state_gaussian_noise (Gau(None, 600) 0 initial_state[0][0] \n____________________________________________________________________________________________________\n" + "-----------------------------------------------------------------------------------\n\t\tTranslationModel instance\n-----------------------------------------------------------------------------------\n_model_type: GroundHogModel\nname: tutorial_model\nmodel_path: trained_models/tutorial_model/\nverbose: True\n\nMODEL params:\n{'SAMPLE_ON_SETS': ['train', 'val'], 'CLIP_C': 1.0, 'HEURISTIC': 0, 'SAMPLING_SAVE_MODE': 'list', 'TRG_LAN': 'pe', 'SAMPLING': 'max_likelihood', 'SAMPLE_EACH_UPDATES': 300, 'N_LAYERS_DECODER': 1, 'TRG_PRETRAINED_VECTORS_TRAINABLE': True, 'USE_PRELU': False, 'POS_UNK': False, 'ENCODER_HIDDEN_SIZE': 256, 'REBUILD_DATASET': True, 'METRICS': ['coco'], 'TOKENIZE_REFERENCES': True, 'OPTIMIZER': 'Adadelta', 'SOURCE_TEXT_EMBEDDING_SIZE': 300, 'EVAL_EACH_EPOCHS': True, 'EPOCHS_FOR_SAVE': 1, 'USE_BATCH_NORMALIZATION': True, 'BATCH_SIZE': 50, 'MODEL_NAME': 'APE_mtpe_GroundHogModel_src_emb_300_bidir_True_enc_LSTM_256_dec_LSTM_256_deepout_linear_trg_emb_300_Adadelta_1.0', 'BATCH_NORMALIZATION_MODE': 1, 'EVAL_ON_SETS_KERAS': [], 'N_SAMPLES': 5, 'RECURRENT_DROPOUT_P': 0.5, 'WEIGHT_DECAY': 0.0001, 'OUTPUTS_IDS_DATASET': ['target_text'], 'INIT_LAYERS': ['tanh'], 'EARLY_STOP': True, 'DATA_AUGMENTATION': False, 'TEXT_FILES': {'test': 'test.', 'train': 'training.', 'val': 'dev.'}, 'MAPPING': '/media/HDD_2TB/DATASETS/APE/in-domain/joint_bpe//mapping.mt_pe.pkl', 'DROPOUT_P': 0.5, 'RECURRENT_WEIGHT_DECAY': 0.0, 'ADDITIONAL_OUTPUT_MERGE_MODE': 'sum', 'PARALLEL_LOADERS': 1, 'ALIGN_FROM_RAW': True, 'SAMPLE_WEIGHTS': True, 'EVAL_EACH': 1, 'EXTRA_NAME': '', 'MIN_OCCURRENCES_INPUT_VOCAB': 0, 'INIT_FUNCTION': 'glorot_uniform', 'LOSS': 'categorical_crossentropy', 'WRITE_VALID_SAMPLES': True, 'INPUTS_IDS_MODEL': ['source_text', 'state_below'], 'MODE': 'training', 'LR_GAMMA': 0.8, 'NOISE_AMOUNT': 0.01, 'SRC_PRETRAINED_VECTORS_TRAINABLE': True, 'STOP_METRIC': 'TER', 'N_LAYERS_ENCODER': 1, 'INPUTS_IDS_DATASET': ['source_text', 'state_below'], 'BIDIRECTIONAL_ENCODER': True, 'MAX_OUTPUT_TEXT_LEN_TEST': 150, 'FORCE_RELOAD_VOCABULARY': False, 'layer': ('linear', 300), 'TOKENIZATION_METHOD': 'tokenize_none', 'OUTPUT_VOCABULARY_SIZE': 516, 'SRC_PRETRAINED_VECTORS': None, 'START_EVAL_ON_EPOCH': 1, 'BEAM_SEARCH': True, 'TARGET_TEXT_EMBEDDING_SIZE': 300, 'DECODER_HIDDEN_SIZE': 256, 'MODEL_TYPE': 'GroundHogModel', 'STORE_PATH': '/media/HDD_2TB/MODELS/APE/trained_models/APE_mtpe_GroundHogModel_src_emb_300_bidir_True_enc_LSTM_256_dec_LSTM_256_deepout_linear_trg_emb_300_Adadelta_1.0/', 'TRG_PRETRAINED_VECTORS': None, 'JOINT_BATCHES': 4, 'CLIP_V': 0.0, 'SKIP_VECTORS_HIDDEN_SIZE': 300, 'NORMALIZE_SAMPLING': True, 'MAX_OUTPUT_TEXT_LEN': 50, 'PAD_ON_BATCH': True, 'START_SAMPLING_ON_EPOCH': 1, 'RNN_TYPE': 'LSTM', 'INPUT_VOCABULARY_SIZE': 689, 'BEAM_SIZE': 6, 'TRAIN_ON_TRAINVAL': False, 'LR': 1.0, 'SRC_LAN': 'mt', 'OPTIMIZED_SEARCH': True, 'CLASSIFIER_ACTIVATION': 'softmax', 'FILL': 'end', 'ALPHA_FACTOR': 0.6, 'TEMPERATURE': 1, 'MAX_INPUT_TEXT_LEN': 50, 'USE_RECURRENT_DROPOUT': False, 'DATASET_STORE_PATH': 'datasets/', 'APPLY_DETOKENIZATION': False, 'PATIENCE': 20, 'SAVE_EACH_EVALUATION': True, 'DATA_ROOT_PATH': '/media/HDD_2TB/DATASETS/APE/in-domain/joint_bpe/', 'HOMOGENEOUS_BATCHES': False, 'LR_DECAY': None, 'DATASET_NAME': 'APE', 'USE_DROPOUT': False, 'TOKENIZE_HYPOTHESES': True, 'VERBOSE': 1, 'MIN_OCCURRENCES_OUTPUT_VOCAB': 0, 'BIDIRECTIONAL_DEEP_ENCODER': True, 'OUTPUTS_IDS_MODEL': ['target_text'], 'USE_NOISE': True, 'DETOKENIZATION_METHOD': 'detokenize_bpe', 'DEEP_OUTPUT_LAYERS': [('linear', 300)], 'RELOAD': 0, 'EVAL_ON_SETS': ['val'], 'MAX_EPOCH': 500, 'USE_L2': False}\n-----------------------------------------------------------------------------------\n____________________________________________________________________________________________________\nLayer (type) Output Shape Param # Connected to \n====================================================================================================\nsource_text (InputLayer) (None, None) 0 \n____________________________________________________________________________________________________\nsource_word_embedding (Embedding (None, None, 300) 206700 source_text[0][0] \n____________________________________________________________________________________________________\nsrc_embedding_gaussian_noise (Ga (None, None, 300) 0 source_word_embedding[0][0] \n____________________________________________________________________________________________________\nsrc_embedding_batch_normalizatio (None, None, 300) 1200 src_embedding_gaussian_noise[0][0\n____________________________________________________________________________________________________\nbidirectional_encoder_LSTM (Bidi (None, None, 512) 1140736 src_embedding_batch_normalization\n____________________________________________________________________________________________________\nannotations_gaussian_noise (Gaus (None, None, 512) 0 bidirectional_encoder_LSTM[0][0] \n____________________________________________________________________________________________________\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "state_below_batch_normalization ((None, None, 420) 840 state_below_gaussian_noise[0][0] \n____________________________________________________________________________________________________\ninitial_state_batch_normalization(None, 600) 1200 initial_state_gaussian_noise[0][0\n____________________________________________________________________________________________________\nattgrucond_2 (AttGRUCond) [(None, None, 600), (N6160201 state_below_batch_normalization[0\n annotations_batch_normalization[0\n initial_state_batch_normalization\n____________________________________________________________________________________________________\nproj_h0_gaussian_noise (GaussianN(None, None, 600) 0 attgrucond_2[0][0] \n____________________________________________________________________________________________________\nproj_h0_batch_normalization (Batc(None, None, 600) 1200 proj_h0_gaussian_noise[0][0] \n____________________________________________________________________________________________________\n" + "annotations_batch_normalization (None, None, 512) 2048 annotations_gaussian_noise[0][0] \n____________________________________________________________________________________________________\nstate_below (InputLayer) (None, None) 0 \n____________________________________________________________________________________________________\nmaskedmean_1 (MaskedMean) (None, 512) 0 annotations_batch_normalization[0\n____________________________________________________________________________________________________\ntarget_word_embedding (Embedding (None, None, 300) 154800 state_below[0][0] \n____________________________________________________________________________________________________\ninitial_state (Dense) (None, 256) 131328 maskedmean_1[0][0] \n____________________________________________________________________________________________________\ninitial_memory (Dense) (None, 256) 131328 maskedmean_1[0][0] \n____________________________________________________________________________________________________\nstate_below_gaussian_noise (Gaus (None, None, 300) 0 target_word_embedding[0][0] \n____________________________________________________________________________________________________\ninitial_state_gaussian_noise (Ga (None, 256) 0 initial_state[0][0] \n____________________________________________________________________________________________________\ninitial_memory_gaussian_noise (G (None, 256) 0 initial_memory[0][0] \n____________________________________________________________________________________________________\nstate_below_batch_normalization (None, None, 300) 1200 state_below_gaussian_noise[0][0] \n____________________________________________________________________________________________________\nmasklayer_1 (MaskLayer) (None, None, 512) 0 annotations_batch_normalization[0\n____________________________________________________________________________________________________\ninitial_state_batch_normalizatio (None, 256) 1024 initial_state_gaussian_noise[0][0\n____________________________________________________________________________________________________\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "logit_ctx (TimeDistributed) multiple 504420 attgrucond_2[0][1] \n____________________________________________________________________________________________________\nlogit_lstm (TimeDistributed) multiple 252420 proj_h0_batch_normalization[0][0]\n____________________________________________________________________________________________________\nlambda_2 (Lambda) (None, None, 420) 0 logit_ctx[0][0] \n____________________________________________________________________________________________________\nlogit_emb (TimeDistributed) multiple 176820 state_below_batch_normalization[0\n____________________________________________________________________________________________________\nout_layer_mlp_gaussian_noise (Gau(None, None, 420) 0 logit_lstm[0][0] \n____________________________________________________________________________________________________\nout_layer_ctx_gaussian_noise (Gau(None, None, 420) 0 lambda_2[0][0] \n____________________________________________________________________________________________________\nout_layer_emb_gaussian_noise (Gau(None, None, 420) 0 logit_emb[0][0] \n____________________________________________________________________________________________________\nout_layer_mlp_batch_normalization(None, None, 420) 840 out_layer_mlp_gaussian_noise[0][0\n____________________________________________________________________________________________________\nout_layer_ctx_batch_normalization(None, None, 420) 840 out_layer_ctx_gaussian_noise[0][0\n____________________________________________________________________________________________________\nout_layer_emb_batch_normalization(None, None, 420) 840 out_layer_emb_gaussian_noise[0][0\n____________________________________________________________________________________________________\nadditional_input (Merge) (None, None, 420) 0 out_layer_mlp_batch_normalization\n out_layer_ctx_batch_normalization\n out_layer_emb_batch_normalization\n____________________________________________________________________________________________________\nactivation_2 (Activation) (None, None, 420) 0 additional_input[0][0] \n____________________________________________________________________________________________________\nmaxout_0 (TimeDistributed) multiple 353640 activation_2[0][0] \n____________________________________________________________________________________________________\nout_layermaxout_gaussian_noise (G(None, None, 210) 0 maxout_0[0][0] \n____________________________________________________________________________________________________\nout_layermaxout_batch_normalizati(None, None, 210) 420 out_layermaxout_gaussian_noise[0]\n____________________________________________________________________________________________________\n" + "initial_memory_batch_normalizati (None, 256) 1024 initial_memory_gaussian_noise[0][\n____________________________________________________________________________________________________\ndecoder_AttLSTMCond (AttLSTMCond [(None, None, 256), ( 1488897 state_below_batch_normalization[0\n masklayer_1[0][0] \n initial_state_batch_normalization\n initial_memory_batch_normalizatio\n____________________________________________________________________________________________________\nproj_h0_gaussian_noise (Gaussian (None, None, 256) 0 decoder_AttLSTMCond[0][0] \n____________________________________________________________________________________________________\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "target_text (TimeDistributed) multiple 108876 out_layermaxout_batch_normalizati\n====================================================================================================\n" + "proj_h0_batch_normalization (Bat (None, None, 256) 1024 proj_h0_gaussian_noise[0][0] \n____________________________________________________________________________________________________\nlogit_ctx (TimeDistributed) multiple 153900 decoder_AttLSTMCond[0][1] \n____________________________________________________________________________________________________\nlogit_lstm (TimeDistributed) multiple 77100 proj_h0_batch_normalization[0][0]\n____________________________________________________________________________________________________\npermutegeneral_1 (PermuteGeneral (None, None, 300) 0 logit_ctx[0][0] \n____________________________________________________________________________________________________\nlogit_emb (TimeDistributed) multiple 90300 state_below_batch_normalization[0\n____________________________________________________________________________________________________\nout_layer_mlp_gaussian_noise (Ga (None, None, 300) 0 logit_lstm[0][0] \n____________________________________________________________________________________________________\nout_layer_ctx_gaussian_noise (Ga (None, None, 300) 0 permutegeneral_1[0][0] \n____________________________________________________________________________________________________\nout_layer_emb_gaussian_noise (Ga (None, None, 300) 0 logit_emb[0][0] \n____________________________________________________________________________________________________\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "out_layer_mlp_batch_normalizatio (None, None, 300) 1200 out_layer_mlp_gaussian_noise[0][0\n____________________________________________________________________________________________________\nout_layer_ctx_batch_normalizatio (None, None, 300) 1200 out_layer_ctx_gaussian_noise[0][0\n____________________________________________________________________________________________________\nout_layer_emb_batch_normalizatio (None, None, 300) 1200 out_layer_emb_gaussian_noise[0][0\n____________________________________________________________________________________________________\nadditional_input (Merge) (None, None, 300) 0 out_layer_mlp_batch_normalization\n out_layer_ctx_batch_normalization\n out_layer_emb_batch_normalization\n____________________________________________________________________________________________________\nactivation_1 (Activation) (None, None, 300) 0 additional_input[0][0] \n____________________________________________________________________________________________________\nlinear_0 (TimeDistributed) multiple 90300 activation_1[0][0] \n____________________________________________________________________________________________________\nout_layerlinear_gaussian_noise ( (None, None, 300) 0 linear_0[0][0] \n____________________________________________________________________________________________________\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "out_layerlinear_batch_normalizat (None, None, 300) 1200 out_layerlinear_gaussian_noise[0]\n____________________________________________________________________________________________________\ntarget_text (TimeDistributed) multiple 155316 out_layerlinear_batch_normalizati\n====================================================================================================\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "30/11/2016_16:33:21: Preparing optimizer and compiling.\n" + "[26/04/2017 13:50:15] Preparing optimizer: Adadelta [LR: 1.0 - LOSS: categorical_crossentropy] and compiling.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "Total params: 12468097\n____________________________________________________________________________________________________\n" + "Total params: 3,833,025\nTrainable params: 3,826,865\nNon-trainable params: 6,160\n____________________________________________________________________________________________________\n" ] } ], "source": [ "nmt_model = TranslationModel(params,\n", - " type='GroundHogModel', \n", + " model_type='GroundHogModel', \n", " model_name='tutorial_model',\n", " vocabularies=dataset.vocabulary,\n", " store_path='trained_models/tutorial_model/',\n", @@ -161,7 +176,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -189,11 +204,11 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "extra_vars = {'language': 'en', \n", + "extra_vars = {'language': 'en',\n", " 'n_parallel_loaders': 8,\n", " 'tokenize_f': eval('dataset.' + 'tokenize_none'),\n", " 'beam_size': 12,\n", @@ -204,32 +219,29 @@ " 'dataset_outputs': ['target_text'],\n", " 'normalize': True,\n", " 'alpha_factor': 0.6,\n", - " 'val':{'references': dataset.extra_variables['val']['target_text']}\n", + " 'val': {'references': dataset.extra_variables['val']['target_text']}\n", " }\n", "\n", "vocab = dataset.vocabulary['target_text']['idx2words']\n", "callbacks = []\n", - "callbacks.append(utils.callbacks.PrintPerformanceMetricOnEpochEnd(nmt_model,\n", - " dataset,\n", - " gt_id='target_text',\n", - " metric_name=['coco'],\n", - " set_name=['val'],\n", - " batch_size=50,\n", - " each_n_epochs=2,\n", - " extra_vars=extra_vars,\n", - " reload_epoch=0,\n", - " is_text=True,\n", - " index2word_y=vocab,\n", - " sampling_type='max_likelihood',\n", - " beam_search=True,\n", - " save_path=nmt_model.model_path,\n", - " start_eval_on_epoch=0,\n", - " write_samples=True,\n", - " write_type='list',\n", - " early_stop=True,\n", - " patience=5,\n", - " stop_metric='Bleu_4',\n", - " verbose=True))" + "callbacks.append(PrintPerformanceMetricOnEpochEndOrEachNUpdates(nmt_model,\n", + " dataset,\n", + " gt_id='target_text',\n", + " metric_name=['coco'],\n", + " set_name=['val'],\n", + " batch_size=50,\n", + " each_n_epochs=2,\n", + " extra_vars=extra_vars,\n", + " reload_epoch=0,\n", + " is_text=True,\n", + " index2word_y=vocab,\n", + " sampling_type='max_likelihood',\n", + " beam_search=True,\n", + " save_path=nmt_model.model_path,\n", + " start_eval_on_epoch=0,\n", + " write_samples=True,\n", + " write_type='list',\n", + " verbose=True))\n" ] }, { @@ -241,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -272,6 +284,14 @@ "source": [ "nmt_model.trainNet(dataset, training_params)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "outputs": [], + "source": [ + "" + ] } ], "metadata": { diff --git a/examples/4_nmt_model_tutorial.ipynb b/examples/4_nmt_model_tutorial.ipynb index c22eae0..c63d12e 100644 --- a/examples/4_nmt_model_tutorial.ipynb +++ b/examples/4_nmt_model_tutorial.ipynb @@ -31,33 +31,16 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Using Theano backend.\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Using gpu device 0: GeForce GTX 1080 (CNMeM is disabled, cuDNN 5105)\n" - ] - } - ], - "source": [ - "from keras.engine import Input\n", - "from keras.layers.embeddings import Embedding\n", - "from keras.layers.recurrent import GRU, AttGRUCond\n", - "from keras.layers import TimeDistributed, Bidirectional\n", - "from keras.layers.core import Dense, Activation, Lambda, MaxoutDense, MaskedMean, PermuteGeneral\n", - "from keras import backend as K\n", - "from keras.engine.topology import merge\n", - "from keras.models import Model" + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from keras.layers import *\n", + "from keras.models import model_from_json, Model\n", + "from keras.optimizers import Adam, RMSprop, Nadam, Adadelta, SGD, Adagrad, Adamax\n", + "from keras.regularizers import l2\n", + "from keras_wrapper.cnn_model import Model_Wrapper\n", + "from keras_wrapper.extra.regularize import Regularize" ] }, { @@ -69,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -90,7 +73,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -120,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -142,11 +125,13 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "ctx_mean = MaskedMean()(annotations)\n", + "annotations = MaskLayer()(annotations) # We may want the padded annotations\n", + "\n", "initial_state = Dense(hidden_state_size, name='initial_state',\n", " activation='tanh')(ctx_mean)" ] @@ -160,7 +145,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -180,7 +165,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -202,7 +187,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -240,7 +225,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -257,7 +242,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -290,7 +275,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -326,7 +311,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -345,7 +330,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -373,7 +358,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -394,15 +379,6 @@ "source": [ "And that's all! For using this model together with the facilities provided by the staged_model_wrapper library, we should declare the model as a method of a Model_Wrapper class. A complete example of this can be found at `model_zoo.py`." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "" - ] } ], "metadata": { From 43891dff7ef71e1f781173e89c7298da2714947e Mon Sep 17 00:00:00 2001 From: lvapeab Date: Wed, 26 Apr 2017 14:50:53 +0200 Subject: [PATCH 17/25] Update docs --- docs/source/conf.py | 29 +- docs/source/index.rst | 1 + docs/source/requirements.rst | 2 +- docs/source/resources.rst | 5 +- docs/source/tutorial.rst | 577 +++++++++++++++++++++++++++++++++++ docs/source/usage.rst | 10 +- 6 files changed, 608 insertions(+), 16 deletions(-) create mode 100644 docs/source/tutorial.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index 55c679a..3e28a5e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,6 +25,7 @@ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' +import sphinx_rtd_theme # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -123,25 +124,37 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = { + 'collapse_navigation': False, + 'display_version': False, + 'navigation_depth': 3, +} + +html_context = { + 'display_github': True, + 'github_repo': "nmt-keras", + 'github_user': "lvapeab", + 'github_version': "master", + 'conf_py_path': "/docs/source/" +} # Add any paths that contain custom themes here, relative to this directory. -# html_theme_path = [] +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # The name for this set of Sphinx documents. # " v documentation" by default. # -# html_title = u'NMT-Keras v0.0.1' +html_title = u'NMT-Keras' # A shorter title for the navigation bar. Default is the same as html_title. # -# html_short_title = None +html_short_title = u'NMT-Keras documentation' # The name of an image file (relative to this directory) to place at the top # of the sidebar. @@ -187,11 +200,11 @@ # If false, no module index is generated. # -# html_domain_indices = True +html_domain_indices = False # If false, no index is generated. # -# html_use_index = True +html_use_index = False # If true, the index is split into individual pages for each letter. # @@ -199,7 +212,7 @@ # If true, links to the reST sources are added to the pages. # -# html_show_sourcelink = True +html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # diff --git a/docs/source/index.rst b/docs/source/index.rst index 769463d..3bfb309 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -32,6 +32,7 @@ Guide requirements usage resources + tutorial help diff --git a/docs/source/requirements.rst b/docs/source/requirements.rst index 425d483..125b1a0 100644 --- a/docs/source/requirements.rst +++ b/docs/source/requirements.rst @@ -1,7 +1,7 @@ Requirements ============ - Our version of Keras_. - - `Multimodal Keras Wrapper`_.::. See the documentation_ and tutorial_. + - `Multimodal Keras Wrapper`_. See the documentation_ and tutorial_. - Coco-caption_ evaluation package (Only required to perform evaluation). .. _Keras: https://github.com/MarcBS/keras diff --git a/docs/source/resources.rst b/docs/source/resources.rst index bf345d8..a6ff0ba 100644 --- a/docs/source/resources.rst +++ b/docs/source/resources.rst @@ -3,7 +3,7 @@ Resources - Overview_ of an attentional NMT system. -- NMT-Keras `step-by-step guide`_: Tutorials for running this library. They are expected to be followed in order: +- NMT-Keras step-by-step guide (iPython_ and html_ versions): Tutorials for running this library. They are expected to be followed in order: 1. `Dataset setup`_: Shows how to invoke and configure a Dataset instance for a translation problem. 2. `Training tutorial`_: Shows how to call a translation model, link it with the dataset object and construct calllbacks for monitorizing the training. @@ -11,7 +11,8 @@ Resources 4. `NMT model tutorial`_: Shows how to build a state-of-the-art NMT model with Keras in few (~50) lines. .. _Overview: https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/neural_machine_translation.pdf -.. _step-by-step guide: https://github.com/lvapeab/nmt-keras/blob/master/examples +.. _iPython: https://github.com/lvapeab/nmt-keras/blob/master/examples +.. _html: ./tutorial.html .. _Dataset setup: https://github.com/lvapeab/nmt-keras/blob/master/examples/1_dataset_tutorial.ipynb .. _Training tutorial: https://github.com/lvapeab/nmt-keras/blob/master/examples/2_training_tutorial.ipynb .. _Decoding tutorial: https://github.com/lvapeab/nmt-keras/blob/master/examples/3_decoding_tutorial.ipynb diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst new file mode 100644 index 0000000..b519f2d --- /dev/null +++ b/docs/source/tutorial.rst @@ -0,0 +1,577 @@ +Tutorials +========= + + +This page contains some examples and tutorials showing how the library works. All tutorials have a `iPython notebook version`_. + +.. _iPython notebook version: https://github.com/lvapeab/nmt-keras/blob/master/examples + +Almost every variable tutorials representing model hyperparameters have been intentionally hardcoded in the tutorials, +aiming to facilitate readability. On a real execution, these values are taken from the `config.py` file. + +All tutorials have been executed from the root `nmt-keras` folder. These tutorials basically are a split version of the execution pipeline of the library. If you run `python main.py`, you'll execute almost the same as tutorials 1, 2 and 4. + +The translation task is *EuTrans* (`Amengual et al.`_), a toy-task mainly used for debugging purposes. + +.. _Amengual et al.: http://link.springer.com/article/10.1023/A:1011116115948 + + +Dataset tutorial +**************** + +First, we'll create a Dataset_ instance, in order to properly manage the data. First, we are creating a Dataset_ object (from the `Multimodal Keras Wrapper`_ library). +Let's make some imports and create an empty Dataset_ instance:: + + from keras_wrapper.dataset import Dataset, saveDataset + from data_engine.prepare_data import keep_n_captions + ds = Dataset('tutorial_dataset', 'tutorial', silence=False) + +.. _Multimodal Keras Wrapper: https://github.com/lvapeab/multimodal_keras_wrapper +.. _Dataset: http://marcbs.github.io/multimodal_keras_wrapper/tutorial.html#basic-components + + +Now that we have the empty Dataset_, we must indicate its inputs and outputs. In our case, we'll have two different inputs and one single output: + +1. Outputs:: + **target_text**: Sentences in the target language. + +2. Inputs:: + **source_text**: Sentences in the source language. + + **state_below**: Sentences in the target language, but shifted one position to the right (for teacher-forcing training of the model). + +For setting up the outputs, we use the setOutputs function, with the appropriate parameters. Note that, when we are building the dataset for the training split, we build the vocabulary (up to 30000 words):: + + ds.setOutput('examples/EuTrans/training.en', + 'train', + type='text', + id='target_text', + tokenization='tokenize_none', + build_vocabulary=True, + pad_on_batch=True, + sample_weights=True, + max_text_len=30, + max_words=30000, + min_occ=0) + + ds.setOutput('examples/EuTrans/dev.en', + 'val', + type='text', + id='target_text', + pad_on_batch=True, + tokenization='tokenize_none', + sample_weights=True, + max_text_len=30, + max_words=0) + +Similarly, we introduce the source text data, with the setInputs function. Again, when building the training split, we must construct the vocabulary:: + + + + ds.setInput('examples/EuTrans/training.es', + 'train', + type='text', + id='source_text', + pad_on_batch=True, + tokenization='tokenize_none', + build_vocabulary=True, + fill='end', + max_text_len=30, + max_words=30000, + min_occ=0) + ds.setInput('examples/EuTrans/dev.es', + 'val', + type='text', + id='source_text', + pad_on_batch=True, + tokenization='tokenize_none', + fill='end', + max_text_len=30, + min_occ=0) + + + + +...and for the `state_below` data. Note that: 1) The offset flat is set to 1, which means that the text will be shifted to the right 1 position. 2) During sampling time, we won't have this input. Hence, we 'hack' the dataset model by inserting an artificial input, of type 'ghost' for the validation split:: + + ds.setInput('examples/EuTrans/training.en', + 'train', + type='text', + id='state_below', + required=False, + tokenization='tokenize_none', + pad_on_batch=True, + build_vocabulary='target_text', + offset=1, + fill='end', + max_text_len=30, + max_words=30000) + ds.setInput(None, + 'val', + type='ghost', + id='state_below', + required=False) + + +Next, we match the references with the inputs, in order to evaluate against the raw references:: + + keep_n_captions(ds, repeat=1, n=1, set_names=['val']) + + +Finally, we can save our dataset instance for using it in other experiments:: + + saveDataset(ds, 'datasets') + + +Training tutorial +***************** +Now, we'll create and train a Neural Machine Translation (NMT) model. +We'll build the so-called `GroundHogModel`. It is defined at the `model_zoo.py` file. +If you followed prior tutorial, you should have a dataset instance. Otherwise, you should follow that notebook first. + +So, let's go! First, we make some imports, load the default parameters and the dataset:: + + from config import load_parameters + from model_zoo import TranslationModel + import utils + from keras_wrapper.cnn_model import loadModel + from keras_wrapper.dataset import loadDataset + params = load_parameters() + dataset = loadDataset('datasets/Dataset_tutorial_dataset.pkl') + +Since the number of words in the dataset may be unknown beforehand, we must update the params information according to the dataset instance:: + + + params['INPUT_VOCABULARY_SIZE'] = dataset.vocabulary_len['source_text'] + params['OUTPUT_VOCABULARY_SIZE'] = dataset.vocabulary_len['target_text'] + +Now, we create a `TranslationModel` object: An instance of a `Model_Wrapper`_ object from `Multimodal Keras Wrapper`_. +We specify the type of the model (`GroundHogModel`) and the vocabularies from the Dataset_:: + + nmt_model = TranslationModel(params, + model_type='GroundHogModel', + model_name='tutorial_model', + vocabularies=dataset.vocabulary, + store_path='trained_models/tutorial_model/', + verbose=True) + +.. _Model_Wrapper: http://marcbs.github.io/multimodal_keras_wrapper/tutorial.html#basic-components + +Now, we must define the inputs and outputs mapping from our Dataset instance to our model:: + + inputMapping = dict() + for i, id_in in enumerate(params['INPUTS_IDS_DATASET']): + pos_source = dataset.ids_inputs.index(id_in) + id_dest = nmt_model.ids_inputs[i] + inputMapping[id_dest] = pos_source + nmt_model.setInputsMapping(inputMapping) + + outputMapping = dict() + for i, id_out in enumerate(params['OUTPUTS_IDS_DATASET']): + pos_target = dataset.ids_outputs.index(id_out) + id_dest = nmt_model.ids_outputs[i] + outputMapping[id_dest] = pos_target + nmt_model.setOutputsMapping(outputMapping) + + + + +We can add some callbacks for controlling the training (e.g. Sampling each N updates, early stop, learning rate annealing...). +For instance, let's build a `PrintPerformanceMetricOnEpochEndOrEachNUpdates` callback. Each 2 epochs, it will compute the 'coco' scores on the development set. +We need to pass some variables to the callback (in the extra_vars dictionary):: + + from keras_wrapper.extra.callbacks import * + extra_vars = {'language': 'en', + 'n_parallel_loaders': 8, + 'tokenize_f': eval('dataset.' + 'tokenize_none'), + 'beam_size': 12, + 'maxlen': 50, + 'model_inputs': ['source_text', 'state_below'], + 'model_outputs': ['target_text'], + 'dataset_inputs': ['source_text', 'state_below'], + 'dataset_outputs': ['target_text'], + 'normalize': True, + 'alpha_factor': 0.6, + 'val':{'references': dataset.extra_variables['val']['target_text']} + } + vocab = dataset.vocabulary['target_text']['idx2words'] + callbacks = [] + callbacks.append(PrintPerformanceMetricOnEpochEnd(nmt_model, + dataset, + gt_id='target_text', + metric_name=['coco'], + set_name=['val'], + batch_size=50, + each_n_epochs=2, + extra_vars=extra_vars, + reload_epoch=0, + is_text=True, + index2word_y=vocab, + sampling_type='max_likelihood', + beam_search=True, + save_path=nmt_model.model_path, + start_eval_on_epoch=0, + write_samples=True, + write_type='list', + save_each_evaluation=True, + verbose=True)) + + +Now we are almost ready to train. We set up some training parameters...:: + + training_params = {'n_epochs': 100, + 'batch_size': 40, + 'maxlen': 30, + 'epochs_for_save': 1, + 'verbose': 0, + 'eval_on_sets': [], + 'n_parallel_loaders': 8, + 'extra_callbacks': callbacks, + 'reload_epoch': 0, + 'epoch_offset': 0} + + + +And train!:: + + nmt_model.trainNet(dataset, training_params) + + +For a description of the training output, refer to the `typical output`_ document. + +.. _typical output: https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/typical_output.md + +Decoding tutorial +***************** + + +Now, we'll load from disk a trained Neural Machine Translation (NMT) model and we'll apply it for translating new text. This is done by the sample_ensemble_ script. + +This tutorial assumes that you followed both previous tutorials. In this case, we want to translate the 'test' split of our dataset. + +As before, let's import some stuff and load the dataset instance:: + + from config import load_parameters + from data_engine.prepare_data import keep_n_captions + from keras_wrapper.cnn_model import loadModel + from keras_wrapper.dataset import loadDataset + params = load_parameters() + dataset = loadDataset('datasets/Dataset_tutorial_dataset.pkl') + + +Since we want to translate a new data split ('test') we must add it to the dataset instance, just as we did before (at the first tutorial). +In case we also had the refences of the test split and we wanted to evaluate it, we can add it to the dataset. Note that this is not mandatory and we could just predict without evaluating.:: + + dataset.setInput('examples/EuTrans/test.es', + 'test', + type='text', + id='source_text', + pad_on_batch=True, + tokenization='tokenize_none', + fill='end', + max_text_len=100, + min_occ=0) + + dataset.setInput(None, + 'test', + type='ghost', + id='state_below', + required=False) + +.. _sample_ensemble: https://github.com/lvapeab/nmt-keras/blob/master/examples/documentation/ensembling_tutorial.md + + +Now, let's load the translation model. Suppose we want to load the model saved at the end of the epoch 4:: + + params['INPUT_VOCABULARY_SIZE'] = dataset.vocabulary_len[params['INPUTS_IDS_DATASET'][0]] + params['OUTPUT_VOCABULARY_SIZE'] = dataset.vocabulary_len[params['OUTPUTS_IDS_DATASET'][0]] + # Load model + nmt_model = loadModel('trained_models/tutorial_model', 4) + nmt_model.setOptimizer() + + + +Once we loaded the model, we just have to invoke the sampling method (in this case, the Beam Search algorithm) for the 'test' split:: + + params_prediction = {'batch_size': 50, + 'n_parallel_loaders': 8, + 'predict_on_sets': ['test'], + 'beam_size': 12, + 'maxlen': 50, + 'model_inputs': ['source_text', 'state_below'], + 'model_outputs': ['target_text'], + 'dataset_inputs': ['source_text', 'state_below'], + 'dataset_outputs': ['target_text'], + 'normalize': True, + 'alpha_factor': 0.6 + } + predictions = nmt_model.predictBeamSearchNet(dataset, params_prediction)['test'] + + +Up to this moment, in the variable 'predictions', we have the indices of the words of the hypotheses. We must decode them into words. For doing this, we'll use the dictionary stored in the dataset object: + + vocab = dataset.vocabulary['target_text']['idx2words'] + predictions = nmt_model.decode_predictions_beam_search(predictions, + vocab, + verbose=params['VERBOSE']) + +Finally, we store the system hypotheses:: + + filepath = nmt_model.model_path+'/' + 'test' + '_sampling.pred' # results file + from keras_wrapper.extra.read_write import list2file + list2file(filepath, predictions) + + + + +If we have the references of this split, we can also evaluate the performance of our system on it. First, we must add them to the dataset object:: + + # In case we had the references of this split, we could also load the split and evaluate on it + dataset.setOutput('examples/EuTrans/test.en', + 'test', + type='text', + id='target_text', + pad_on_batch=True, + tokenization='tokenize_none', + sample_weights=True, + max_text_len=30, + max_words=0) + keep_n_captions(dataset, repeat=1, n=1, set_names=['test']) + + + +Next, we call the evaluation system: The Coco-caption_ package. Although its main usage is for multimodal captioning, we can use it in machine translation:: + + + from keras_wrapper.extra import evaluation + metric = 'coco' + # Apply sampling + extra_vars = dict() + extra_vars['tokenize_f'] = eval('dataset.' + 'tokenize_none') + extra_vars['test'] = dict() + extra_vars['test']['references'] = dataset.extra_variables['test']['target_text'] + metrics = evaluation.select[metric](pred_list=predictions, + verbose=1, + extra_vars=extra_vars, + split='test') + +.. _Coco-caption: https://github.com/lvapeab/coco-caption + + +NMT model tutorial +****************** + + + +In this module, we are going to create an encoder-decoder model with: + + * A bidirectional GRU encoder and a GRU decoder + * An attention model + * The previously generated word feeds back de decoder + * MLPs for initializing the initial RNN state + * Skip connections from inputs to outputs + * Beam search. + +As usual, first we import the necessary stuff:: + + from keras.layers import * + from keras.models import model_from_json, Model + from keras.optimizers import Adam, RMSprop, Nadam, Adadelta, SGD, Adagrad, Adamax + from keras.regularizers import l2 + from keras_wrapper.cnn_model import Model_Wrapper + from keras_wrapper.extra.regularize import Regularize + +And define the dimesnions of our model. For instance, a word embedding size of 50 and 100 units in RNNs. +The inputs/outpus are defined as in previous tutorials.:: + + ids_inputs = ['source_text', 'state_below'] + ids_outputs = ['target_text'] + word_embedding_size = 50 + hidden_state_size = 100 + input_vocabulary_size=686 # Autoset in the library + output_vocabulary_size=513 # Autoset in the library + +Now, let's define our encoder. First, we have to create an Input layer to connect the input text to our model. +Next, we'll apply a word embedding to the sequence of input indices. This word embedding will feed a Bidirectional GRU network, which will produce our sequence of annotations:: + + # 1. Source text input + src_text = Input(name=ids_inputs[0], + batch_shape=tuple([None, None]), # Since the input sequences have variable-length, we do not retrict the Input shape + dtype='int32') + # 2. Encoder + # 2.1. Source word embedding + src_embedding = Embedding(input_vocabulary_size, word_embedding_size, + name='source_word_embedding', mask_zero=True # Zeroes as mask + )(src_text) + # 2.2. BRNN encoder (GRU/LSTM) + annotations = Bidirectional(GRU(hidden_state_size, + return_sequences=True # Return the full sequence + ), + name='bidirectional_encoder', + merge_mode='concat')(src_embedding) + + + +Once we have built the encoder, let's build our decoder. +First, we have an additional input: The previously generated word (the so-called state_below). We introduce it by means of an Input layer and a (target language) word embedding:: + + # 3. Decoder + # 3.1.1. Previously generated words as inputs for training -> Teacher forcing + next_words = Input(name=ids_inputs[1], batch_shape=tuple([None, None]), dtype='int32') + # 3.1.2. Target word embedding + state_below = Embedding(output_vocabulary_size, word_embedding_size, + name='target_word_embedding', + mask_zero=True)(next_words) + + + +The initial hidden state of the decoder's GRU is initialized by means of a MLP (in this case, single-layered) from the average of the annotations. We also aplly the mask to the annotations:: + + + ctx_mean = MaskedMean()(annotations) + annotations = MaskLayer()(annotations) # We may want the padded annotations + initial_state = Dense(hidden_state_size, name='initial_state', + activation='tanh')(ctx_mean) + +So, we have the input of our decoder:: + + input_attentional_decoder = [state_below, annotations, initial_state] + + + +Note that, for a sample, the sequence of annotations and initial state is the same, independently of the decoding time-step. +In order to avoid computation time, we build two models, one for training and the other one for sampling. +They will share weights, but the sampling model will be made up of two different models. One (model_init) will compute the sequence of annotations and initial_state. +The other model (model_next) will compute a single recurrent step, given the sequence of annotations, the previous hidden state and the generated words up to this moment. + +Therefore, now we slightly change the form of declaring layers. We must share layers between the decoding models. + +So, let's start by building the attentional-conditional GRU:: + + # Define the AttGRUCond function + sharedAttGRUCond = AttGRUCond(hidden_state_size, + return_sequences=True, + return_extra_variables=True, # Return attended input and attenton weights + return_states=True # Returns the sequence of hidden states (see discussion above) + ) + [proj_h, x_att, alphas, h_state] = sharedAttGRUCond(input_attentional_decoder) # Apply shared_AttnGRUCond to our input + +Now, we set skip connections between input and output layer. Note that, since we have a temporal dimension because of the RNN decoder, we must apply the layers in a TimeDistributed way. +Finally, we will merge all skip-connections and apply a 'tanh' no-linearlity:: + + # Define layer function + shared_FC_mlp = TimeDistributed(Dense(word_embedding_size, activation='linear',), + name='logit_lstm') + # Apply layer function + out_layer_mlp = shared_FC_mlp(proj_h) + + # Define layer function + shared_FC_ctx = TimeDistributed(Dense(word_embedding_size, activation='linear'), + name='logit_ctx') + # Apply layer function + out_layer_ctx = shared_FC_ctx(x_att) + shared_Lambda_Permute = PermuteGeneral((1, 0, 2)) + out_layer_ctx = shared_Lambda_Permute(out_layer_ctx) + + # Define layer function + shared_FC_emb = TimeDistributed(Dense(word_embedding_size, activation='linear'), + name='logit_emb') + # Apply layer function + out_layer_emb = shared_FC_emb(state_below) + + additional_output = merge([out_layer_mlp, out_layer_ctx, out_layer_emb], mode='sum', name='additional_input') + shared_activation_tanh = Activation('tanh') + out_layer = shared_activation_tanh(additional_output) + +Now, we'll' apply a deep output layer, with Maxout activation:: + + shared_maxout = TimeDistributed(MaxoutDense(word_embedding_size), name='maxout_layer') + out_layer = shared_maxout(out_layer) + + +Finally, we apply a softmax function for obtaining a probability distribution over the target vocabulary words at each timestep:: + + shared_FC_soft = TimeDistributed(Dense(output_vocabulary_size, + activation='softmax', + name='softmax_layer'), + name=ids_outputs[0]) + softout = shared_FC_soft(out_layer) + +That's all! We built a NMT Model! + +NMT models for decoding +^^^^^^^^^^^^^^^^^^^^^^^ + +Now, let's build the models required for sampling. Recall that we are building two models, one for encoding the inputs and the other one for advancing steps in the decoding stage. + +Let's start with model_init. It will take the usual inputs (src_text and state_below) and will output: + +1. The vector probabilities (for timestep 1). +2. The sequence of annotations (from encoder). +3. The current decoder's hidden state. + +The only restriction here is that the first output must be the output layer (probabilities) of the model.:: + + model_init = Model(input=[src_text, next_words], output=[softout, annotations, h_state]) + # Store inputs and outputs names for model_init + ids_inputs_init = ids_inputs + + # first output must be the output probs. + ids_outputs_init = ids_outputs + ['preprocessed_input', 'next_state'] + + + +Next, we will be the model_next. It will have the following inputs: + + * Preprocessed input + * Previously generated word + * Previous hidden state + +And the following outputs: + + * Model probabilities + * Current hidden state + +First, we define the inputs:: + + preprocessed_size = hidden_state_size*2 # Because we have a bidirectional encoder + preprocessed_annotations = Input(name='preprocessed_input', shape=tuple([None, preprocessed_size])) + prev_h_state = Input(name='prev_state', shape=tuple([hidden_state_size])) + input_attentional_decoder = [state_below, preprocessed_annotations, prev_h_state] + + +And now, we build the model, using the functions stored in the 'shared*' variables declared before:: + + # Apply decoder + [proj_h, x_att, alphas, h_state] = sharedAttGRUCond(input_attentional_decoder) + out_layer_mlp = shared_FC_mlp(proj_h) + out_layer_ctx = shared_FC_ctx(x_att) + out_layer_ctx = shared_Lambda_Permute(out_layer_ctx) + out_layer_emb = shared_FC_emb(state_below) + additional_output = merge([out_layer_mlp, out_layer_ctx, out_layer_emb], mode='sum', name='additional_input') + out_layer = shared_activation_tanh(additional_output) + out_layer = shared_maxout(out_layer) + softout = shared_FC_soft(out_layer) + model_next = Model(input=[next_words, preprocessed_annotations, prev_h_state], + output=[softout, preprocessed_annotations, h_state]) + +Finally, we store inputs/outputs for model_next. In addition, we create a couple of dictionaries, matching inputs/outputs from the different models (model_init->model_next, model_nex->model_next):: + + # Store inputs and outputs names for model_next + # first input must be previous word + ids_inputs_next = [ids_inputs[1]] + ['preprocessed_input', 'prev_state'] + # first output must be the output probs. + ids_outputs_next = ids_outputs + ['preprocessed_input', 'next_state'] + + # Input -> Output matchings from model_init to model_next and from model_next to model_nextxt + matchings_init_to_next = {'preprocessed_input': 'preprocessed_input', 'next_state': 'prev_state'} + matchings_next_to_next = {'preprocessed_input': 'preprocessed_input', 'next_state': 'prev_state'} + + + + +And that's all! For using this model together with the facilities provided by the staged_model_wrapper library, we should declare the model as a method of a Model_Wrapper class. +A complete example of this with additional features can be found at model_zoo.py_. + + +.. _model_zoo.py: https://github.com/lvapeab/nmt-keras/blob/master/model_zoo.py \ No newline at end of file diff --git a/docs/source/usage.rst b/docs/source/usage.rst index ddf1378..bffdac3 100644 --- a/docs/source/usage.rst +++ b/docs/source/usage.rst @@ -5,15 +5,15 @@ Training ******** 1) Set a training configuration in the config.py_ script. Each parameter is commented. See the `documentation file`_ for further info about each specific hyperparameter. You can also specify the parameters when calling the `main.py`_ script following the syntax `Key=Value` -2) Train!: - python main.py +2) Train!:: + python main.py Decoding ******** Once we have our model trained, we can translate new text using the `sample_ensemble.py`_ script. Please refer to the `ensembling tutorial`_ for more details about this script. -In short, if we want to use the models from the first three epochs to translate the `examples/EuTrans/test.en` file, just run::: +In short, if we want to use the models from the first three epochs to translate the `examples/EuTrans/test.en` file, just run:: python sample_ensemble.py --models trained_models/tutorial_model/epoch_1 \ trained_models/tutorial_model/epoch_2 \ @@ -21,9 +21,9 @@ In short, if we want to use the models from the first three epochs to translate --text examples/EuTrans/test.en Scoring -******** +******* -The `score.py`_ script can be used to obtain the (-log)probabilities of a parallel corpus. Its syntax is the following::: +The `score.py`_ script can be used to obtain the (-log)probabilities of a parallel corpus. Its syntax is the following:: python score.py --help usage: Use several translation models for scoring source--target pairs From 3ec8533718196a069d89b9536b19a75985cbe0e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Peris?= Date: Wed, 26 Apr 2017 15:18:17 +0200 Subject: [PATCH 18/25] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 702cae5..3c4fc8f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Neural Machine Translation with Keras (+ Theano backend). +Library documentation: [nmt-keras.readthedocs.io](https://nmt-keras.readthedocs.io)





From b55db847d798c11937a1a4218840315bd3326480 Mon Sep 17 00:00:00 2001 From: lvapeab Date: Wed, 26 Apr 2017 17:05:32 +0200 Subject: [PATCH 19/25] Docstrings --- config.py | 27 +++++++++++----------- data_engine/prepare_data.py | 6 ++--- main.py | 2 +- meta-optimizers/spearmint/spearmint_opt.py | 11 +++++++++ model_zoo.py | 5 ++-- utils/evaluate_from_file.py | 17 ++++++++++---- utils/preprocess_binary_word_vectors.py | 6 +++++ utils/preprocess_text_word_vectors.py | 6 +++++ 8 files changed, 56 insertions(+), 24 deletions(-) diff --git a/config.py b/config.py index ba2601c..8155c2d 100644 --- a/config.py +++ b/config.py @@ -6,10 +6,11 @@ def load_parameters(): """ # Input data params - DATASET_NAME = 'EuTrans' # Task name - SRC_LAN = 'en' # Language of the source text - TRG_LAN = 'es' # Language of the target text - DATA_ROOT_PATH = 'examples/%s/' % DATASET_NAME # Path where data is stored + DATASET_NAME = 'APE' # Task name + SRC_LAN = 'mt' # Language of the source text + TRG_LAN = 'pe' # Language of the target text + #DATA_ROOT_PATH = 'examples/%s/' % DATASET_NAME # Path where data is stored + DATA_ROOT_PATH = '/media/HDD_2TB/DATASETS/%s/in-domain/joint_bpe/' % DATASET_NAME # Path where data is stored # SRC_LAN or TRG_LAN will be added to the file names TEXT_FILES = {'train': 'training.', # Data files @@ -62,7 +63,7 @@ def load_parameters(): # Word representation params TOKENIZATION_METHOD = 'tokenize_none' # Select which tokenization we'll apply. # See Dataset class (from stager_keras_wrapper) for more info. - DETOKENIZATION_METHOD = 'tokenize_none' # Select which de-tokenization method we'll apply + DETOKENIZATION_METHOD = 'detokenize_bpe' # Select which de-tokenization method we'll apply APPLY_DETOKENIZATION = False # Wheter we apply a detokenization method @@ -94,8 +95,8 @@ def load_parameters(): LOSS = 'categorical_crossentropy' CLASSIFIER_ACTIVATION = 'softmax' - OPTIMIZER = 'Adam' # Optimizer - LR = 0.001 # Learning rate. Recommended values - Adam 0.001 - Adadelta 1.0 + OPTIMIZER = 'Adadelta' # Optimizer + LR = 1. # Learning rate. Recommended values - Adam 0.001 - Adadelta 1.0 CLIP_C = 1. # During training, clip L2 norm of gradients to this value (0. means deactivated) CLIP_V = 0. # During training, clip absolute value of gradients to this value (0. means deactivated) SAMPLE_WEIGHTS = True # Select whether we use a weights matrix (mask) for the data outputs @@ -117,33 +118,33 @@ def load_parameters(): EARLY_STOP = True # Turns on/off the early stop protocol PATIENCE = 20 # We'll stop if the val STOP_METRIC does not improve after this # number of evaluations - STOP_METRIC = 'Bleu_4' # Metric for the stop + STOP_METRIC = 'TER' # Metric for the stop # Model parameters MODEL_TYPE = 'GroundHogModel' # Model to train. See model_zoo() for the supported architectures RNN_TYPE = 'LSTM' # RNN unit type ('LSTM' and 'GRU' supported) INIT_FUNCTION = 'glorot_uniform' # Initialization function for matrices (see keras/initializations.py) - SOURCE_TEXT_EMBEDDING_SIZE = 420 # Source language word embedding size. + SOURCE_TEXT_EMBEDDING_SIZE = 300 # Source language word embedding size. SRC_PRETRAINED_VECTORS = None # Path to pretrained vectors (e.g.: DATA_ROOT_PATH + '/DATA/word2vec.%s.npy' % SRC_LAN) # Set to None if you don't want to use pretrained vectors. # When using pretrained word embeddings. this parameter must match with the word embeddings size SRC_PRETRAINED_VECTORS_TRAINABLE = True # Finetune or not the target word embedding vectors. - TARGET_TEXT_EMBEDDING_SIZE = 420 # Source language word embedding size. + TARGET_TEXT_EMBEDDING_SIZE = 300 # Source language word embedding size. TRG_PRETRAINED_VECTORS = None # Path to pretrained vectors. (e.g. DATA_ROOT_PATH + '/DATA/word2vec.%s.npy' % TRG_LAN) # Set to None if you don't want to use pretrained vectors. # When using pretrained word embeddings, the size of the pretrained word embeddings must match with the word embeddings size. TRG_PRETRAINED_VECTORS_TRAINABLE = True # Finetune or not the target word embedding vectors. # Encoder configuration - ENCODER_HIDDEN_SIZE = 600 # For models with RNN encoder + ENCODER_HIDDEN_SIZE = 256 # For models with RNN encoder BIDIRECTIONAL_ENCODER = True # Use bidirectional encoder N_LAYERS_ENCODER = 1 # Stack this number of encoding layers BIDIRECTIONAL_DEEP_ENCODER = True # Use bidirectional encoder in all encoding layers # Decoder configuration - DECODER_HIDDEN_SIZE = 600 # For models with RNN decoder + DECODER_HIDDEN_SIZE = 256 # For models with RNN decoder N_LAYERS_DECODER = 1 # Stack this number of decoding layers. ADDITIONAL_OUTPUT_MERGE_MODE = 'sum' # Merge mode for the skip-connections # Skip connections size @@ -192,7 +193,7 @@ def load_parameters(): MODEL_NAME += EXTRA_NAME - STORE_PATH = 'trained_models/' + MODEL_NAME + '/' # Models and evaluation results will be stored here + STORE_PATH = '/media/HDD_2TB/MODELS/%s/trained_models/%s/' % (DATASET_NAME, MODEL_NAME) # Models and evaluation results will be stored here DATASET_STORE_PATH = 'datasets/' # Dataset instance will be stored here SAMPLING_SAVE_MODE = 'list' # 'list' or 'vqa' diff --git a/data_engine/prepare_data.py b/data_engine/prepare_data.py index dfb8420..5a656bf 100644 --- a/data_engine/prepare_data.py +++ b/data_engine/prepare_data.py @@ -214,9 +214,9 @@ def keep_n_captions(ds, repeat, n=1, set_names=None): """ Keeps only n captions per image and stores the rest in dictionaries for a later evaluation :param ds: Dataset object - :param repeat: - :param n: - :param set_names: + :param repeat: Number of input samples per output + :param n: Number of outputs to keep. + :param set_names: Set name. :return: """ diff --git a/main.py b/main.py index 8c7dc1b..d062ac7 100644 --- a/main.py +++ b/main.py @@ -339,7 +339,7 @@ def buildCallbacks(params, model, dataset): def check_params(params): """ Checks some typical parameters and warns if something wrong was specified. - :param params: Model instance on which to apply the callback. + :param params: Model instance on which to apply the callback. :return: None """ if params['POS_UNK']: diff --git a/meta-optimizers/spearmint/spearmint_opt.py b/meta-optimizers/spearmint/spearmint_opt.py index 4d2a7bd..48282b8 100644 --- a/meta-optimizers/spearmint/spearmint_opt.py +++ b/meta-optimizers/spearmint/spearmint_opt.py @@ -17,6 +17,11 @@ d = dict(os.environ.copy()) d['LC_NUMERIC'] = 'en_US.utf-8' def invoke_model(parameters): + """ + Loads a model, trains it and evaluates it. + :param parameters: Model parameters + :return: Metric to minimize value. + """ model_params = load_parameters() model_name = model_params["MODEL_TYPE"] @@ -51,6 +56,12 @@ def invoke_model(parameters): def main(job_id, params): + """ + Launches the spearmint job + :param job_id: Job identifier. + :param params: Model parameters. + :return: Metric to minimize value. + """ print params return invoke_model(params) diff --git a/model_zoo.py b/model_zoo.py index 8783a31..f989388 100644 --- a/model_zoo.py +++ b/model_zoo.py @@ -119,8 +119,7 @@ def setParams(self, params): def setOptimizer(self, **kwargs): """ - Sets a new optimizer for the Translation_Model. - + Sets and compiles a new optimizer for the Translation_Model. :param kwargs: :return: """ @@ -191,6 +190,8 @@ def setOptimizer(self, **kwargs): def __str__(self): """ Plots basic model information. + + :return: String containing model information. """ obj_str = '-----------------------------------------------------------------------------------\n' class_name = self.__class__.__name__ diff --git a/utils/evaluate_from_file.py b/utils/evaluate_from_file.py index bea977e..86c2180 100644 --- a/utils/evaluate_from_file.py +++ b/utils/evaluate_from_file.py @@ -12,8 +12,6 @@ from pycocoevalcap.rouge.rouge import Rouge from pycocoevalcap.meteor.meteor import Meteor from pycocoevalcap.ter.ter import Ter -ROOT_PATH = '/media/HDD_2TB/DATASETS/' - parser = argparse.ArgumentParser( description="""This takes two files and a path the references (source, references), @@ -26,6 +24,12 @@ def load_textfiles(references, hypothesis): + """ + Loads the references and hypothesis text files. + :param references: Path to the references files. + :param hypothesis: Path to the hypotheses file. + :return: + """ print "The number of references is {}".format(len(references)) hypo = {idx: [lines.strip()] for (idx, lines) in enumerate(hypothesis)} # take out newlines before creating dictionary @@ -41,9 +45,12 @@ def load_textfiles(references, hypothesis): def CocoScore(ref, hypo, language='en'): """ - ref, dictionary of reference sentences (id, sentence) - hypo, dictionary of hypothesis sentences (id, sentence) - score, dictionary of scores + Obtains the COCO scores from the references and hypotheses. + + :param ref: Dictionary of reference sentences (id, sentence) + :param hypo: Dictionary of hypothesis sentences (id, sentence) + :param language: Language of the sentences (for METEOR) + :return: dictionary of scores """ scorers = [ (Bleu(4), ["Bleu_1", "Bleu_2", "Bleu_3", "Bleu_4"]), diff --git a/utils/preprocess_binary_word_vectors.py b/utils/preprocess_binary_word_vectors.py index 47419b7..cead2af 100644 --- a/utils/preprocess_binary_word_vectors.py +++ b/utils/preprocess_binary_word_vectors.py @@ -15,6 +15,12 @@ def word2vec2npy(v_path, base_path_save, dest_filename): + """ + Preprocess pretrained binary vectors and stores them in a suitable format (.npy) + :param v_path: Path to the binary vectors file. + :param base_path_save: Path where the formatted vectors will be stored. + :param dest_filename: Filename of the formatted vectors. + """ word_vecs = dict() print "Loading vectors from %s" % v_path diff --git a/utils/preprocess_text_word_vectors.py b/utils/preprocess_text_word_vectors.py index 4e80654..77d834a 100644 --- a/utils/preprocess_text_word_vectors.py +++ b/utils/preprocess_text_word_vectors.py @@ -15,6 +15,12 @@ def txtvec2npy(v_path, base_path_save, dest_filename): + """ + Preprocess pretrained text vectors and stores them in a suitable format (.npy) + :param v_path: Path to the text vectors file. + :param base_path_save: Path where the formatted vectors will be stored. + :param dest_filename: Filename of the formatted vectors. + """ vecs_dict = dict() print "Loading vectors from %s" % v_path From 9156a60be7c2ff0038b581d6d5d621f36200b97c Mon Sep 17 00:00:00 2001 From: lvapeab Date: Wed, 26 Apr 2017 17:31:01 +0200 Subject: [PATCH 20/25] Update docs --- docs/source/conf.py | 32 ++++++++++---------------------- docs/source/requirements.rst | 1 + model_zoo.py | 30 ++++++++++++++++++++++-------- 3 files changed, 33 insertions(+), 30 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 3e28a5e..0484a7d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,24 +1,9 @@ # -*- coding: utf-8 -*- -# -# NMT-Keras documentation build configuration file, created by -# sphinx-quickstart on Tue Apr 25 15:21:41 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) +import os +import sys +sys.path.append(os.path.abspath('../..')) + # -- General configuration ------------------------------------------------ @@ -39,6 +24,9 @@ # Add any paths that contain templates here, relative to this directory. templates_path = ['ntemplates'] +edit_on_github_project = 'lvapeab/nmt-keras' +edit_on_github_branch = 'master' + # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # @@ -200,11 +188,11 @@ # If false, no module index is generated. # -html_domain_indices = False +html_domain_indices = True # If false, no index is generated. # -html_use_index = False +html_use_index = True # If true, the index is split into individual pages for each letter. # @@ -334,7 +322,7 @@ # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'NMT-Keras', u'NMT-Keras Documentation', - author, 'NMT-Keras', 'One line description of project.', + author, 'NMT-Keras', 'Neural Machine Translation with Keras', 'Miscellaneous'), ] diff --git a/docs/source/requirements.rst b/docs/source/requirements.rst index 125b1a0..32b7eef 100644 --- a/docs/source/requirements.rst +++ b/docs/source/requirements.rst @@ -1,5 +1,6 @@ Requirements ============ + - Our version of Keras_. - `Multimodal Keras Wrapper`_. See the documentation_ and tutorial_. - Coco-caption_ evaluation package (Only required to perform evaluation). diff --git a/model_zoo.py b/model_zoo.py index f989388..c8ea464 100644 --- a/model_zoo.py +++ b/model_zoo.py @@ -12,10 +12,22 @@ class TranslationModel(Model_Wrapper): """ Translation model class. Instance of the Model_Wrapper class (see staged_keras_wrapper). - """ - def resumeTrainNet(self, ds, params, out_name=None): - pass + :param params: all hyperparams of the model. + :param model_type: network name type (corresponds to any method defined in the section 'MODELS' of this class). + Only valid if 'structure_path' == None. + :param verbose: set to 0 if you don't want the model to output informative messages + :param structure_path: path to a Keras' model json file. + If we speficy this parameter then 'type' will be only an informative parameter. + :param weights_path: path to the pre-trained weights file (if None, then it will be randomly initialized) + :param model_name: optional name given to the network + (if None, then it will be assigned to current time as its name) + :param vocabularies: vocabularies used for word embedding + :param store_path: path to the folder where the temporal model packups will be stored + :param set_optimizer: Compile optimizer or not. + :param clear_dirs: Clean model directories or not. + + """ def __init__(self, params, model_type='Translation_Model', verbose=1, structure_path=None, weights_path=None, model_name=None, vocabularies=None, store_path=None, set_optimizer=True, clear_dirs=True): @@ -218,14 +230,16 @@ def __str__(self): def GroundHogModel(self, params): """ Neural machine translation with: - * BLSTM encoder + * BRNN encoder * Attention mechansim on input sequence of annotations - * Conditional LSTM for decoding - * Feed forward layers: - + Context projected to output - + Last word projected to output + * Conditional RNN for decoding + * Deep output layers: + * Context projected to output + * Last word projected to output * Possibly deep encoder/decoder + See https://arxiv.org/abs/1409.0473 for an in-depth review of the model. + :param params: Dictionary of params (see config.py) :return: None """ From 194d624e3ed935fb38f68a89ef91c2957fc76f21 Mon Sep 17 00:00:00 2001 From: lvapeab Date: Wed, 26 Apr 2017 17:49:00 +0200 Subject: [PATCH 21/25] Updated docs --- data_engine/prepare_data.py | 2 +- docs/source/conf.py | 2 +- docs/source/data_engine.rst | 23 +++++++++++++++++++ docs/source/index.rst | 12 ++++++---- docs/source/modules.rst | 9 ++++++++ docs/source/nmt-keras.rst | 30 ++++++++++++++++++++++++ docs/source/tutorial.rst | 2 +- docs/source/utils.rst | 46 +++++++++++++++++++++++++++++++++++++ utils/evaluate_from_file.py | 4 +++- 9 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 docs/source/data_engine.rst create mode 100644 docs/source/modules.rst create mode 100644 docs/source/nmt-keras.rst create mode 100644 docs/source/utils.rst diff --git a/data_engine/prepare_data.py b/data_engine/prepare_data.py index 5a656bf..a656cc4 100644 --- a/data_engine/prepare_data.py +++ b/data_engine/prepare_data.py @@ -7,7 +7,7 @@ def update_dataset_from_file(ds, input_text_filename, params, - splits=list('val'), + splits=list(['val']), output_text_filename=None, remove_outputs=False, compute_state_below=False): diff --git a/docs/source/conf.py b/docs/source/conf.py index 0484a7d..6ceecac 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -2,7 +2,7 @@ import os import sys -sys.path.append(os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath('../../')) # -- General configuration ------------------------------------------------ diff --git a/docs/source/data_engine.rst b/docs/source/data_engine.rst new file mode 100644 index 0000000..432bc3c --- /dev/null +++ b/docs/source/data_engine.rst @@ -0,0 +1,23 @@ +data_engine package +=================== + +Submodules +---------- + + +prepare_data module +------------------- + +.. automodule:: data_engine.prepare_data + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule::data_engine + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/index.rst b/docs/source/index.rst index 3bfb309..3ff657e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,8 +3,13 @@ NMT-Keras Neural Machine Translation with Keras (+ Theano backend). +.. image:: ../../examples/documentation/attention_nmt_model.png + :scale: 80 % + :alt: alternate text + :align: left + Features -======== +******** * Attention model over the input sequence of annotations. * Peeked decoder: The previously generated word is an input of the current timestep. @@ -22,10 +27,8 @@ Features .. _Glove: http://nlp.stanford.edu/projects/glove/ .. _Word2Vec: https://code.google.com/archive/p/word2vec/ - - Guide -***** +===== .. toctree:: :maxdepth: 3 @@ -33,6 +36,7 @@ Guide usage resources tutorial + modules help diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 0000000..8b3c75d --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,9 @@ +Modules +======= + +.. toctree:: + :maxdepth: 4 + + nmt-keras + data_engine + utils \ No newline at end of file diff --git a/docs/source/nmt-keras.rst b/docs/source/nmt-keras.rst new file mode 100644 index 0000000..6e6f268 --- /dev/null +++ b/docs/source/nmt-keras.rst @@ -0,0 +1,30 @@ +nmt-keras package +================= + +Submodules +---------- + +main module +----------- + +.. automodule:: main + :members: + :undoc-members: + :show-inheritance: + +model_zoo module +---------------- + +.. automodule:: model_zoo + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: nmt-keras + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/tutorial.rst b/docs/source/tutorial.rst index b519f2d..e720037 100644 --- a/docs/source/tutorial.rst +++ b/docs/source/tutorial.rst @@ -308,7 +308,7 @@ Once we loaded the model, we just have to invoke the sampling method (in this ca predictions = nmt_model.predictBeamSearchNet(dataset, params_prediction)['test'] -Up to this moment, in the variable 'predictions', we have the indices of the words of the hypotheses. We must decode them into words. For doing this, we'll use the dictionary stored in the dataset object: +Up to this moment, in the variable 'predictions', we have the indices of the words of the hypotheses. We must decode them into words. For doing this, we'll use the dictionary stored in the dataset object:: vocab = dataset.vocabulary['target_text']['idx2words'] predictions = nmt_model.decode_predictions_beam_search(predictions, diff --git a/docs/source/utils.rst b/docs/source/utils.rst new file mode 100644 index 0000000..a7a7588 --- /dev/null +++ b/docs/source/utils.rst @@ -0,0 +1,46 @@ +utils package +============= + +Submodules +---------- + +evaluate_from_file module +------------------------- + +.. automodule:: utils.evaluate_from_file + :members: + :undoc-members: + :show-inheritance: + +preprocess_binary_word_vectors module +------------------------------------- + +.. automodule:: utils.preprocess_binary_word_vectors + :members: + :undoc-members: + :show-inheritance: + +preprocess_text_word_vectors module +----------------------------------- + +.. automodule:: utils.preprocess_text_word_vectors + :members: + :undoc-members: + :show-inheritance: + +utils module +------------ + +.. automodule:: utils.utils + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: utils + :members: + :undoc-members: + :show-inheritance: diff --git a/utils/evaluate_from_file.py b/utils/evaluate_from_file.py index 86c2180..2e258e1 100644 --- a/utils/evaluate_from_file.py +++ b/utils/evaluate_from_file.py @@ -1,3 +1,5 @@ +import argparse + """ Scores a file of hypothesis. Usage: @@ -5,7 +7,6 @@ 2. python evaluate_from_file.py -hyp hypothesis -r references """ -import argparse from pycocoevalcap.bleu.bleu import Bleu from pycocoevalcap.cider.cider import Cider @@ -26,6 +27,7 @@ def load_textfiles(references, hypothesis): """ Loads the references and hypothesis text files. + :param references: Path to the references files. :param hypothesis: Path to the hypotheses file. :return: From 4c9bbcdb4b70e46b484ef466f94c11ddf34226b0 Mon Sep 17 00:00:00 2001 From: lvapeab Date: Wed, 26 Apr 2017 18:22:54 +0200 Subject: [PATCH 22/25] Requirements file --- docs/source/help.rst | 8 +++++--- requirements.txt | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 requirements.txt diff --git a/docs/source/help.rst b/docs/source/help.rst index 13a757d..e8678ef 100644 --- a/docs/source/help.rst +++ b/docs/source/help.rst @@ -1,13 +1,15 @@ -Help -==== +Contact +======= If you have any trouble using NMT-Keras, please drop an email to: lvapeab@prhlt.upv.es Acknowledgement ^^^^^^^^^^^^^^^ -Much of this library has been developed together with `Marc Bolaños`_ for other sequence-to-sequence problems. +Much of this library has been developed together with `Marc Bolaños`_ for other multimodal projects. +Related projects +^^^^^^^^^^^^^^^^ To see other projects following the philosophy of NMT-Keras, take a look to: * TMA_: for egocentric captioning based on temporally-linked sequences. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..06d73a9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +cloud +h5py +-e git+https://github.com/MarcBS/keras.git#egg=keras +-e git+https://github.com/MarcBS/multimodal_keras_wrapper.git#egg=keras_wrapper +-e git+https://github.com/lvapeab/coco-caption.git#egg=coco-caption +matplotlib +numpy +pygpu +scikit-image +six +-e git+https://github.com/lvapeab/Spearmint@f8bf0486b69d4cfb0b4d6dc98a9d469f7a08f86b#egg=spearmint +tables +Theano +toolz \ No newline at end of file From 1eeb7ffdf94666583d6196de264b3e9bd8ebdeda Mon Sep 17 00:00:00 2001 From: lvapeab Date: Wed, 26 Apr 2017 18:36:34 +0200 Subject: [PATCH 23/25] Update requirements --- requirements.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 06d73a9..aad66a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,10 +5,8 @@ h5py -e git+https://github.com/lvapeab/coco-caption.git#egg=coco-caption matplotlib numpy -pygpu scikit-image six --e git+https://github.com/lvapeab/Spearmint@f8bf0486b69d4cfb0b4d6dc98a9d469f7a08f86b#egg=spearmint tables Theano toolz \ No newline at end of file From 5aa3794bfecb1ab6bd3c0ef0edc9898d17cb06c2 Mon Sep 17 00:00:00 2001 From: lvapeab Date: Thu, 27 Apr 2017 09:49:32 +0200 Subject: [PATCH 24/25] Update requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index aad66a7..7f08875 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ h5py matplotlib numpy scikit-image +scikit-learn six tables Theano From 2cdc3fb27f3021017093c8dc1d27856643fb2b56 Mon Sep 17 00:00:00 2001 From: lvapeab Date: Thu, 27 Apr 2017 09:54:09 +0200 Subject: [PATCH 25/25] Update docs maxdepth --- docs/source/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 3ff657e..a076075 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -30,7 +30,7 @@ Features Guide ===== .. toctree:: - :maxdepth: 3 + :maxdepth: 2 requirements usage