From f2614638407e83f760510beca517641a0f61eb5b Mon Sep 17 00:00:00 2001 From: "vitali.zhelezniak" Date: Tue, 13 Feb 2018 14:47:16 +0000 Subject: [PATCH] Decoding Decoders --- .gitignore | 173 +++++++ LICENSE | 201 ++++++++ NOTICE | 13 + README.md | 188 +++++++ WORKSPACE | 0 images/unroll.png | Bin 0 -> 374813 bytes requirements.txt | 7 + sent_eval/evaluation/__init__.py | 0 sent_eval/evaluation/similarity_context.py | 136 +++++ sent_eval/evaluation/similarity_unroll.py | 203 ++++++++ sent_eval/evaluation/transfer_context.py | 135 +++++ sent_eval/evaluation/transfer_unroll.py | 198 ++++++++ setup.py | 16 + skip_thoughts/BUILD | 94 ++++ skip_thoughts/README.md | 475 +++++++++++++++++ skip_thoughts/__init__.py | 0 skip_thoughts/configuration.py | 146 ++++++ skip_thoughts/data/BUILD | 23 + skip_thoughts/data/__init__.py | 0 skip_thoughts/data/preprocess_dataset.py | 308 ++++++++++++ skip_thoughts/data/special_words.py | 27 + skip_thoughts/decode.py | 161 ++++++ skip_thoughts/encoder_manager.py | 140 ++++++ skip_thoughts/evaluate.py | 117 +++++ skip_thoughts/experiments.py | 51 ++ skip_thoughts/ops/BUILD | 17 + skip_thoughts/ops/__init__.py | 0 skip_thoughts/ops/gru_cell.py | 134 +++++ skip_thoughts/ops/input_ops.py | 119 +++++ skip_thoughts/pretrained_embeddings.py | 97 ++++ skip_thoughts/skip_thoughts_encoder.py | 262 ++++++++++ skip_thoughts/skip_thoughts_model.py | 559 +++++++++++++++++++++ skip_thoughts/summaries.py | 34 ++ skip_thoughts/track_perplexity.py | 199 ++++++++ skip_thoughts/train.py | 245 +++++++++ skip_thoughts/vocabulary_expansion.py | 203 ++++++++ unrolling_the_decoder.md | 115 +++++ 37 files changed, 4796 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 NOTICE create mode 100644 README.md create mode 100644 WORKSPACE create mode 100644 images/unroll.png create mode 100644 requirements.txt create mode 100644 sent_eval/evaluation/__init__.py create mode 100644 sent_eval/evaluation/similarity_context.py create mode 100644 sent_eval/evaluation/similarity_unroll.py create mode 100644 sent_eval/evaluation/transfer_context.py create mode 100644 sent_eval/evaluation/transfer_unroll.py create mode 100644 setup.py create mode 100644 skip_thoughts/BUILD create mode 100644 skip_thoughts/README.md create mode 100644 skip_thoughts/__init__.py create mode 100644 skip_thoughts/configuration.py create mode 100644 skip_thoughts/data/BUILD create mode 100644 skip_thoughts/data/__init__.py create mode 100644 skip_thoughts/data/preprocess_dataset.py create mode 100644 skip_thoughts/data/special_words.py create mode 100644 skip_thoughts/decode.py create mode 100644 skip_thoughts/encoder_manager.py create mode 100644 skip_thoughts/evaluate.py create mode 100644 skip_thoughts/experiments.py create mode 100644 skip_thoughts/ops/BUILD create mode 100644 skip_thoughts/ops/__init__.py create mode 100644 skip_thoughts/ops/gru_cell.py create mode 100644 skip_thoughts/ops/input_ops.py create mode 100644 skip_thoughts/pretrained_embeddings.py create mode 100644 skip_thoughts/skip_thoughts_encoder.py create mode 100644 skip_thoughts/skip_thoughts_model.py create mode 100644 skip_thoughts/summaries.py create mode 100644 skip_thoughts/track_perplexity.py create mode 100644 skip_thoughts/train.py create mode 100644 skip_thoughts/vocabulary_expansion.py create mode 100644 unrolling_the_decoder.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b16bf79 --- /dev/null +++ b/.gitignore @@ -0,0 +1,173 @@ +### Project +sent_eval/data/senteval_data +skip_thoughts/model + +/bazel-bin +/bazel-ci_build-cache +/bazel-genfiles +/bazel-out +/bazel-skip_thoughts +/bazel-testlogs +/bazel-tf +*.pyc +*~ + + +### macOS template +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/ + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + + +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject +sent_eval/examples/glove/ +results/ +.snakemake/ +.swp + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..37ce346 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Babylon Partners. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..c739223 --- /dev/null +++ b/NOTICE @@ -0,0 +1,13 @@ +Decoding Decoders +Copyright 2018 Babylon Partners. + +This repository includes software developed +at Babylon Partners (babylonhealth.com). + +Portions of this software were developed by +The TensorFlow Authors. +https://github.com/tensorflow/models/blob/master/AUTHORS + +This software contains code derived from +The TensorFlow Authors. +https://github.com/tensorflow/models/blob/master/AUTHORS diff --git a/README.md b/README.md new file mode 100644 index 0000000..02c40ba --- /dev/null +++ b/README.md @@ -0,0 +1,188 @@ +# Decoding Decoders: Finding Optimal Representation Spaces for Unsupervised Similarity Tasks + +TensorFlow implementation of the models described in the +[Decoding Decoders](https://openreview.net/forum?id=SJOOAEJwf) paper. + +This codebase builds on top of [Tensorflow Skip-Thought](https://github.com/tensorflow/models/tree/master/research/skip_thoughts) implementation by Chris Shallue +and uses [SentEval](https://github.com/facebookresearch/SentEval) from Facebook for evaluations on transfer tasks. + +The aim is to study how different choices of decoders affect the performance on unsupervised similarity tasks, such as STS. + + +## Contents +* [Requirements](#requirements) +* [Data Preprocessing](#data-preprocessing) +* [Training](#training) +* [Vocabulary Expansion](#vocabulary-expansion) +* [Evaluation](#evaluation) + +## Requirements + +This code uses Python 2.7. Please install the requirements in `requirements.txt`. + + +## Data Preprocessing + +### Preparation + +You will need to obtain the BookCorpus dataset from [this website](http://yknzhu.wixsite.com/mbweb). + +### Quick run +```shell + +# Comma-separated list of globs matching the input files. The format of +# the input files is assumed to be a list of newline-separated sentences, where +# each sentence is already tokenized. +INPUT_FILES= + +# Location to save the preprocessed training and validation data. +DATA_DIR= + +# Run the preprocessing script. +python -m skip_thoughts.data.preprocess_dataset \ + --input_files=${INPUT_FILES} \ + --output_dir=${DATA_DIR} +``` + + +## Training + +### Training params +We added a couple of new parameters in the `train.py` script. +The most important ones are described here, please see the code to see additional functionality we have added. + +**`--decoder=SEQxSKGy`** where `x`, `y` can be `0`, `1`, `2`, and `3`. + +SEQ stands for sequence (recurrent) decoder and SKG stands for bag-of-words (BOW) decoder. +* `0` - no decoder of this type is present +* `1` - decoder for the current sentence (Autoencoder) +* `2` - decoders for the previous and next sentences (Skip-Though/FastSent style) +* `3` - decoders for previous, current, and next sentences (Skip-Thought + Autoencoder) +Note that it is possible to combine SEQ and SKG + +**`--skipgram_encoder=True|False`** + +* `True` The architecture has a bag-of-words (BOW) encoder. +* `False` The architecture has a sequence (RNN) encoder. + +Defaults to `False`. + +### Quick run +```shell +# Directory containing the preprocessed data. +DATA_DIR= + +# Directory to save the model. Note: A new folder will be created in here called run_{unixtimestamp}. Into this folder, the model checkpoints will be saved. Also, the FLAGS wile, as well as its dict and json representations will be stored as `flags.pkl`, `config.pkl` and `config.json` respectively. +RUN_DIR= + +# Model decoder configuration (choose one of SEQ0SKG2 SEQ0SKG3 SEQ2SKG2 or SEQ3SKG3) +DECODER="SEQ0SKG2" + +# Whether to use skipgram (BOW) encoder (choose True or False). Defaults to False. +SKIPGRAM_ENCODER=False + +# Run the training script. + +python -m skip_thoughts.train \ + --input_file_pattern="${DATA_DIR}/train-?????-of-00100" \ + --run_dir="${RUN_DIR}" \ + --decoder="${DECODER}" \ + --skipgram_encoder="${SKIPGRAM_ENCODER}" +``` +This will train a model with an RNN encoder and 2 BOW decoders. + +## Vocabulary Expansion + +### Preparation + +You will need to download the pretrained Google News word2vec vectors, found [here](https://code.google.com/archive/p/word2vec/). +Please see the SkipThought readme for more details on vocab expansion. + +### Quick run +```shell +MODEL_DIR= +SKIP_THOUGHTS_VOCAB= +W2VMODEL= +LOG_FILE= + +python -m skip_thoughts.vocabulary_expansion \ + --skip_thoughts_model="${MODEL_DIR}" \ + --skip_thoughts_vocab="${SKIP_THOUGHTS_VOCAB}" \ + --word2vec_model="${W2VMODEL}" \ + --output_dir="${MODEL_DIR}" \ + > "${LOG_FILE}" 2>&1 +``` + + +## Evaluation + +### Preparation + +You will need to clone the [SentEval repo](https://github.com/facebookresearch/SentEval) and download the data as instructed there. +Then copy our scripts from `sent_eval/evaluation` to the `examples` directory to run. + +### The scripts + +The [`SentEval` evaluation scripts](/sent_eval/evaluation) either use the encoder output (which we confusingly call `context` here), or the unrolled decoder (which we less confusingly call `unroll` for the similarity and transfer tasks. + +The similarity scripts +[similarity_context.py](/sent_eval/evaluation/similarity_context.py) and +[similarity_unroll.py](/sent_eval/evaluation/similarity_context.py) +run the `STS*` tasks (`STS12`, `STS13`, `STS14`, `STS15` and `STS16`) of `SentEval`. + +The transfer scripts +[transfer_context.py](/sent_eval/evaluation/transfer_context.py) and +[transfer_unroll.py](/sent_eval/evaluation/transfer_context.py) +run the transfer tasks (`CR`, `MR`, `MPQA`, `SUBJ`, `SST`, `TREC`, `MRPC`, + `SICKRelatedness`, `SICKEntailment` and `STSBenchmark`) of `SentEval`. + +Each script runs with 10-fold cross validation, and saves the dictionary of all results as a pickle to the desired location. This can then be used for easy generation of plots and other analysis. + +#### Context + +The context scripts +[similarity_context.py](/sent_eval/evaluation/similarity_context.py) and +[transfer_context.py](/sent_eval/evaluation/transfer_context.py) work for all decoder types. + +The parameters of the context scripts are: + ++ `--model_dir` The path to the saved model you want to evaluate. Specifically, this should include this should be a folder containined checkpoint and decoder configuration information produced by [`train.py`](/skip_thoughts/train.py). ++ `--output_results_path` The full path to save the pickle file containing all of the results from this evaluation. + +#### Unroll + +The unroll scripts +[similarity_unroll.py](/sent_eval/evaluation/similarity_context.py) and +[transfer_unroll.py](/sent_eval/evaluation/transfer_context.py) only work for RNN decoder types, and use the [decoder unrolling mechanism](/unrolling_the_decoder.md) discussed in the [Decoding Decoders](https://openreview.net/forum?id=SJOOAEJwf) paper. + +In addition to the parameters of the context scripts (above), the unroll scripts require the following parameters: + ++ `--unroll_length` This should be a positive integer, and corresponds to how many time steps each decoder will "unroll" to produce the sentence representation. ++ `--decoder_type` This should be either `'mean'` or `'concat'` and corresponds to either taking the sentence representation as the mean or concatentation over the unrolled hidden states respectively. + +### Quick run +The example below is for running `similarity_context.py`, the exact same process will work for the other evaluation scripts. +```shell +# Directory to load the model from +MODEL_DIR= + +# Which GPU(s) to use (choose from e.g. one of [0 1 0,1]) +GPU_IDS=0 + +# Log file +LOG_FILE= + +# Pickle save path +PICKLE_PATH= + +# Run the evaluation script. +CUDA_VISIBLE_DEVICES=$GPU_IDS \ + python -m sent_eval.evaluation.similarity_context \ + --model_dir="${MODEL_DIR}" \ + --output_results_path="${PICKLE_PATH}" \ + > "${LOG_FILE}" 2>&1 +``` + +## Contact + +Vitalii Zhelezniak diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..e69de29 diff --git a/images/unroll.png b/images/unroll.png new file mode 100644 index 0000000000000000000000000000000000000000..480b604912ddce7fc54e76735181370b3b05a1fe GIT binary patch literal 374813 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

UP2M6hQIvoV= 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 j+@M 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�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≷w1_xmX~d% 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 G^Zx;-4ut0b literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6d433d2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +gensim==3.2.0 +nltk==3.2.4 +numpy==1.13.1 +scikit-learn==0.19.0 +scipy==0.19.1 +tensorflow==1.3.0 +tqdm==4.15.0 diff --git a/sent_eval/evaluation/__init__.py b/sent_eval/evaluation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sent_eval/evaluation/similarity_context.py b/sent_eval/evaluation/similarity_context.py new file mode 100644 index 0000000..ab3a555 --- /dev/null +++ b/sent_eval/evaluation/similarity_context.py @@ -0,0 +1,136 @@ +# Copyright 2018 Babylon Partners. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import cPickle +import sys + +from skip_thoughts import configuration +from skip_thoughts import encoder_manager + +import tensorflow as tf + +import logging +import skip_thoughts.experiments as experiments + +from sent_eval.examples.exutil import dotdict + + +FLAGS = tf.flags.FLAGS + + +tf.flags.DEFINE_string("model_dir", None, + "Directory for saving and loading checkpoints.") +tf.flags.DEFINE_string("output_results_path", None, + "Path to save pickled results to.") +tf.flags.DEFINE_bool("use_eos", True, + "If to use the eos token during encoder unroll.") + +if not FLAGS.model_dir: + raise ValueError("--model_dir is required.") +if not FLAGS.output_results_path: + raise ValueError("--output_results_path is required.") + +# Set paths to the model. +VOCAB_FILE = os.path.join(FLAGS.model_dir, "vocab.txt") +EMBEDDING_MATRIX_FILE = os.path.join(FLAGS.model_dir, "embeddings.npy") +CHECKPOINT_PATH = FLAGS.model_dir +FLAGS_PICKLE_PATH = os.path.join(FLAGS.model_dir, "flags.pkl") + +# Load the configuration used to make the model +with open(FLAGS_PICKLE_PATH, 'r') as f: + model_flags = cPickle.load(f) + +decoder_config = experiments.get_decoder_config(flags=model_flags) +model_config = configuration.model_config( + input_file_pattern=model_flags.input_file_pattern, + vocab_size=model_flags.vocab_size, + batch_size=model_flags.batch_size, + word_embedding_dim=model_flags.word_dim, + encoder_dim=model_flags.encoder_dim, + skipgram_encoder=model_flags.skipgram_encoder, + sequence_decoder_pre=decoder_config.sequence_decoder_pre, + sequence_decoder_cur=decoder_config.sequence_decoder_cur, + sequence_decoder_post=decoder_config.sequence_decoder_post, + skipgram_decoder_pre=decoder_config.skipgram_decoder_pre, + skipgram_decoder_cur=decoder_config.skipgram_decoder_cur, + skipgram_decoder_post=decoder_config.skipgram_decoder_post, + share_weights_logits=model_flags.share_weights_logits, + normalise_decoder_losses=model_flags.normalise_decoder_losses, + skipgram_prefactor=model_flags.skipgram_prefactor, + sequence_prefactor=model_flags.sequence_prefactor) + +# Set up the encoder. Here we are using a single unidirectional model. +# To use a bidirectional model as well, call load_model() again with +# configuration.model_config(bidirectional_encoder=True) and paths to the +# bidirectional model's files. The encoder will use the concatenation of +# all loaded models. +encoder = encoder_manager.EncoderManager() +encoder.load_model(model_config=model_config, + vocabulary_file=VOCAB_FILE, + embedding_matrix_file=EMBEDDING_MATRIX_FILE, + checkpoint_path=CHECKPOINT_PATH) + +# encodings = encoder.encode(data) + + +# Set PATHs +current_path = os.path.dirname(__file__) +PATH_TO_SENTEVAL = os.path.join(current_path, '../') +PATH_TO_DATA = os.path.join(current_path, '../data/senteval_data') + +# import SentEval +sys.path.insert(0, PATH_TO_SENTEVAL) +import senteval + + +# consider the option of lower-casing or not for bow. +def prepare(params, samples): + params.batch_size = 128 + # set to 10 to be comparable to published results + params.kfold = 10 + return + + +def batcher(params, batch): + batch = [" ".join(sent) if sent != [] else " ".join(['.']) + for sent in batch] + return encoder.encode(batch, use_eos=FLAGS.use_eos) + + +# Set params for SentEval +params_senteval = {'task_path': PATH_TO_DATA, 'usepytorch': False, 'kfold': 10} +params_senteval = dotdict(params_senteval) + +# Set up logger +logging.basicConfig(format='%(asctime)s : %(message)s', level=logging.DEBUG) + +transfer_tasks = ['CR', 'MR', 'MPQA', 'SUBJ', 'SST', 'TREC', 'MRPC', + 'SICKRelatedness', 'SICKEntailment', 'STSBenchmark', + 'SNLI', 'ImageCaptionRetrieval'] + +similarity_tasks = ['STS12', 'STS13', 'STS14', 'STS15', 'STS16'] + +if __name__ == "__main__": + se = senteval.SentEval(params_senteval, batcher, prepare) + tasks = similarity_tasks + results = se.eval(tasks) + f = open(FLAGS.output_results_path, 'wb') + cPickle.dump(results, f) + f.close() diff --git a/sent_eval/evaluation/similarity_unroll.py b/sent_eval/evaluation/similarity_unroll.py new file mode 100644 index 0000000..6de661e --- /dev/null +++ b/sent_eval/evaluation/similarity_unroll.py @@ -0,0 +1,203 @@ +# Copyright 2018 Babylon Partners. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import cPickle +import sys + +from skip_thoughts import configuration +from skip_thoughts import decode +from skip_thoughts import encoder_manager +from skip_thoughts import experiments + +import numpy as np +import tensorflow as tf + +import logging + +from sent_eval.examples.exutil import dotdict + + +FLAGS = tf.flags.FLAGS + + +tf.flags.DEFINE_string("model_dir", None, + "Directory for saving and loading checkpoints.") +tf.flags.DEFINE_string("output_results_path", None, + "Path to save pickled results to.") +tf.flags.DEFINE_bool("use_eos", True, + "If to use the eos token during encoder unroll.") +tf.flags.DEFINE_integer("unroll_length", None, + "If to use the eos token during encoder unroll.") +tf.flags.DEFINE_string("decoder_type", None, + "If to use the eos token during encoder unroll.") + +if not FLAGS.model_dir: + raise ValueError("--model_dir is required.") +if not FLAGS.output_results_path: + raise ValueError("--output_results_path is required.") +if not FLAGS.unroll_length: + raise ValueError("--unroll_length is required.") + +decoder_types = ['mean', 'concat'] +if FLAGS.decoder_type not in decoder_types: + raise ValueError("--decoder_type must be one of {t}".format(t=decoder_types)) + +# Set paths to the model. +VOCAB_FILE = os.path.join(FLAGS.model_dir, "vocab.txt") +EMBEDDING_MATRIX_FILE = os.path.join(FLAGS.model_dir, "embeddings.npy") +CHECKPOINT_PATH = FLAGS.model_dir +FLAGS_PICKLE_PATH = os.path.join(FLAGS.model_dir, "flags.pkl") + +# Load the configuration used to make the model +with open(FLAGS_PICKLE_PATH, 'r') as f: + model_flags = cPickle.load(f) + +decoder_config = experiments.get_decoder_config(flags=model_flags) +model_config = configuration.model_config( + input_file_pattern=model_flags.input_file_pattern, + vocab_size=model_flags.vocab_size, + batch_size=model_flags.batch_size, + word_embedding_dim=model_flags.word_dim, + encoder_dim=model_flags.encoder_dim, + skipgram_encoder=model_flags.skipgram_encoder, + sequence_decoder_pre=decoder_config.sequence_decoder_pre, + sequence_decoder_cur=decoder_config.sequence_decoder_cur, + sequence_decoder_post=decoder_config.sequence_decoder_post, + skipgram_decoder_pre=decoder_config.skipgram_decoder_pre, + skipgram_decoder_cur=decoder_config.skipgram_decoder_cur, + skipgram_decoder_post=decoder_config.skipgram_decoder_post, + share_weights_logits=model_flags.share_weights_logits, + normalise_decoder_losses=model_flags.normalise_decoder_losses, + skipgram_prefactor=model_flags.skipgram_prefactor, + sequence_prefactor=model_flags.sequence_prefactor) + +# Set up the encoder. Here we are using a single unidirectional model. +# To use a bidirectional model as well, call load_model() again with +# configuration.model_config(bidirectional_encoder=True) and paths to the +# bidirectional model's files. The encoder will use the concatenation of +# all loaded models. +encoder = encoder_manager.EncoderManager() +encoder.load_model(model_config=model_config, + vocabulary_file=VOCAB_FILE, + embedding_matrix_file=EMBEDDING_MATRIX_FILE, + checkpoint_path=CHECKPOINT_PATH, + mode='encode-decode') + +# Build the decoder +g = encoder.graph +sess = encoder.sessions[0] + +tensor_names_global = { + 'word_embedding': 'word_embedding:0'} + +tensor_names_pre = { + 'logits': 'logits/logits/decoder_pre:0', + 'decoder_output': 'decoder_pre/decoder_output:0', + 'decoder_state': 'decoder_pre/decoder_state:0'} + +tensor_names_post = { + 'logits': 'logits_1/logits/decoder_post:0', + 'decoder_output': 'decoder_post/decoder_output:0', + 'decoder_state': 'decoder_post/decoder_state:0'} + +decoder_pre = decode.Decoder( + g=g, + tensor_names_decoder=tensor_names_pre, + tensor_names_global=tensor_names_global) + +decoder_post = decode.Decoder( + g=g, + tensor_names_decoder=tensor_names_post, + tensor_names_global=tensor_names_global) + + +# encodings = encoder.encode(data) + + +# Set PATHs +current_path = os.path.dirname(__file__) +PATH_TO_SENTEVAL = os.path.join(current_path, '../') +PATH_TO_DATA = os.path.join(current_path, '../data/senteval_data') + +# import SentEval +sys.path.insert(0, PATH_TO_SENTEVAL) +import senteval + + +# consider the option of lower-casing or not for bow. +def prepare(params, samples): + params.batch_size = 128 + # set to 10 to be comparable to published results + params.kfold = 10 + return + + +def batcher_steps(steps, decoder_type): + def batcher(params, batch): + batch = [" ".join(sent) if sent != [] else " ".join(['.']) + for sent in batch] + + decode_pre_rep, decode_post_rep = decode.decode( + sess=sess, data=batch, + encoder=encoder, + decoder_pre=decoder_pre, + decoder_post=decoder_post, + steps=steps, + use_eos=FLAGS.use_eos) + + decode_rep_concat = np.concatenate( + (np.array(decode_pre_rep), np.array(decode_post_rep)), axis=1) + + if decoder_type == 'mean': + return np.mean(decode_rep_concat, axis=1) + + this_batch_size = len(decode_rep_concat) + return np.reshape(decode_rep_concat, (this_batch_size, -1)) + + return batcher + + +# Set params for SentEval +params_senteval = {'task_path': PATH_TO_DATA, 'usepytorch': False, 'kfold': 10} +params_senteval = dotdict(params_senteval) + +# Set up logger +logging.basicConfig(format='%(asctime)s : %(message)s', level=logging.DEBUG) + +transfer_tasks = ['CR', 'MR', 'MPQA', 'SUBJ', 'SST', 'TREC', 'MRPC', + 'SICKRelatedness', 'SICKEntailment', 'STSBenchmark', + 'SNLI', 'ImageCaptionRetrieval'] + +similarity_tasks = ['STS12', 'STS13', 'STS14', 'STS15', 'STS16'] + +if __name__ == "__main__": + print( + "Building batcher with unroll length {ul} and decoder type {d}".format( + ul=FLAGS.unroll_length, d=FLAGS.decoder_type)) + + batcher = batcher_steps(steps=FLAGS.unroll_length, + decoder_type=FLAGS.decoder_type) + + se = senteval.SentEval(params_senteval, batcher, prepare) + tasks = similarity_tasks + results = se.eval(tasks) + f = open(FLAGS.output_results_path, 'wb') + cPickle.dump(results, f) + f.close() diff --git a/sent_eval/evaluation/transfer_context.py b/sent_eval/evaluation/transfer_context.py new file mode 100644 index 0000000..8f5ef4d --- /dev/null +++ b/sent_eval/evaluation/transfer_context.py @@ -0,0 +1,135 @@ +# Copyright 2018 Babylon Partners. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import cPickle +import sys + +from skip_thoughts import configuration +from skip_thoughts import encoder_manager + +import tensorflow as tf + +import logging +import skip_thoughts.experiments as experiments + +from sent_eval.examples.exutil import dotdict + + +FLAGS = tf.flags.FLAGS + + +tf.flags.DEFINE_string("model_dir", None, + "Directory for saving and loading checkpoints.") +tf.flags.DEFINE_string("output_results_path", None, + "Path to save pickled results to.") +tf.flags.DEFINE_bool("use_eos", True, + "If to use the eos token during encoder unroll.") + +if not FLAGS.model_dir: + raise ValueError("--model_dir is required.") +if not FLAGS.output_results_path: + raise ValueError("--output_results_path is required.") + +# Set paths to the model. +VOCAB_FILE = os.path.join(FLAGS.model_dir, "vocab.txt") +EMBEDDING_MATRIX_FILE = os.path.join(FLAGS.model_dir, "embeddings.npy") +CHECKPOINT_PATH = FLAGS.model_dir +FLAGS_PICKLE_PATH = os.path.join(FLAGS.model_dir, "flags.pkl") + +# Load the configuration used to make the model +with open(FLAGS_PICKLE_PATH, 'r') as f: + model_flags = cPickle.load(f) + +decoder_config = experiments.get_decoder_config(flags=model_flags) +model_config = configuration.model_config( + input_file_pattern=model_flags.input_file_pattern, + vocab_size=model_flags.vocab_size, + batch_size=model_flags.batch_size, + word_embedding_dim=model_flags.word_dim, + encoder_dim=model_flags.encoder_dim, + skipgram_encoder=model_flags.skipgram_encoder, + sequence_decoder_pre=decoder_config.sequence_decoder_pre, + sequence_decoder_cur=decoder_config.sequence_decoder_cur, + sequence_decoder_post=decoder_config.sequence_decoder_post, + skipgram_decoder_pre=decoder_config.skipgram_decoder_pre, + skipgram_decoder_cur=decoder_config.skipgram_decoder_cur, + skipgram_decoder_post=decoder_config.skipgram_decoder_post, + share_weights_logits=model_flags.share_weights_logits, + normalise_decoder_losses=model_flags.normalise_decoder_losses, + skipgram_prefactor=model_flags.skipgram_prefactor, + sequence_prefactor=model_flags.sequence_prefactor) + +# Set up the encoder. Here we are using a single unidirectional model. +# To use a bidirectional model as well, call load_model() again with +# configuration.model_config(bidirectional_encoder=True) and paths to the +# bidirectional model's files. The encoder will use the concatenation of +# all loaded models. +encoder = encoder_manager.EncoderManager() +encoder.load_model(model_config=model_config, + vocabulary_file=VOCAB_FILE, + embedding_matrix_file=EMBEDDING_MATRIX_FILE, + checkpoint_path=CHECKPOINT_PATH) + +# encodings = encoder.encode(data) + + +# Set PATHs +current_path = os.path.dirname(__file__) +PATH_TO_SENTEVAL = os.path.join(current_path, '../') +PATH_TO_DATA = os.path.join(current_path, '../data/senteval_data') + +# import SentEval +sys.path.insert(0, PATH_TO_SENTEVAL) +import senteval + + +# consider the option of lower-casing or not for bow. +def prepare(params, samples): + params.batch_size = 128 + # set to 10 to be comparable to published results + params.kfold = 10 + return + + +def batcher(params, batch): + batch = [" ".join(sent) if sent != [] else " ".join(['.']) + for sent in batch] + return encoder.encode(batch, use_eos=FLAGS.use_eos) + + +# Set params for SentEval +params_senteval = {'task_path': PATH_TO_DATA, 'usepytorch': False, 'kfold': 10} +params_senteval = dotdict(params_senteval) + +# Set up logger +logging.basicConfig(format='%(asctime)s : %(message)s', level=logging.DEBUG) + +transfer_tasks = ['CR', 'MR', 'MPQA', 'SUBJ', 'SST', 'TREC', 'MRPC', + 'SICKRelatedness', 'SICKEntailment', 'STSBenchmark'] + +similarity_tasks = ['STS12', 'STS13', 'STS14', 'STS15', 'STS16'] + +if __name__ == "__main__": + se = senteval.SentEval(params_senteval, batcher, prepare) + tasks = transfer_tasks + results = se.eval(tasks) + f = open(FLAGS.output_results_path, 'wb') + cPickle.dump(results, f) + f.close() diff --git a/sent_eval/evaluation/transfer_unroll.py b/sent_eval/evaluation/transfer_unroll.py new file mode 100644 index 0000000..99a1862 --- /dev/null +++ b/sent_eval/evaluation/transfer_unroll.py @@ -0,0 +1,198 @@ +# Copyright 2018 Babylon Partners. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import cPickle +import sys + +from skip_thoughts import configuration +from skip_thoughts import decode +from skip_thoughts import encoder_manager +from skip_thoughts import experiments + +import numpy as np +import tensorflow as tf + +import logging + +from sent_eval.examples.exutil import dotdict + + +FLAGS = tf.flags.FLAGS + + +tf.flags.DEFINE_string("model_dir", None, + "Directory for saving and loading checkpoints.") +tf.flags.DEFINE_string("output_results_path", None, + "Path to save pickled results to.") +tf.flags.DEFINE_bool("use_eos", True, + "If to use the eos token during encoder unroll.") +tf.flags.DEFINE_integer("unroll_length", None, + "If to use the eos token during encoder unroll.") +tf.flags.DEFINE_string("decoder_type", None, + "If to use the eos token during encoder unroll.") + +if not FLAGS.model_dir: + raise ValueError("--model_dir is required.") +if not FLAGS.output_results_path: + raise ValueError("--output_results_path is required.") +if not FLAGS.unroll_length: + raise ValueError("--unroll_length is required.") + +decoder_types = ['mean', 'concat'] +if FLAGS.decoder_type not in decoder_types: + raise ValueError("--decoder_type must be one of {t}".format(t=decoder_types)) + +# Set paths to the model. +VOCAB_FILE = os.path.join(FLAGS.model_dir, "vocab.txt") +EMBEDDING_MATRIX_FILE = os.path.join(FLAGS.model_dir, "embeddings.npy") +CHECKPOINT_PATH = FLAGS.model_dir +FLAGS_PICKLE_PATH = os.path.join(FLAGS.model_dir, "flags.pkl") + +# Load the configuration used to make the model +with open(FLAGS_PICKLE_PATH, 'r') as f: + model_flags = cPickle.load(f) + +decoder_config = experiments.get_decoder_config(flags=model_flags) +model_config = configuration.model_config( + input_file_pattern=model_flags.input_file_pattern, + vocab_size=model_flags.vocab_size, + batch_size=model_flags.batch_size, + word_embedding_dim=model_flags.word_dim, + encoder_dim=model_flags.encoder_dim, + skipgram_encoder=model_flags.skipgram_encoder, + sequence_decoder_pre=decoder_config.sequence_decoder_pre, + sequence_decoder_cur=decoder_config.sequence_decoder_cur, + sequence_decoder_post=decoder_config.sequence_decoder_post, + skipgram_decoder_pre=decoder_config.skipgram_decoder_pre, + skipgram_decoder_cur=decoder_config.skipgram_decoder_cur, + skipgram_decoder_post=decoder_config.skipgram_decoder_post, + share_weights_logits=model_flags.share_weights_logits, + normalise_decoder_losses=model_flags.normalise_decoder_losses, + skipgram_prefactor=model_flags.skipgram_prefactor, + sequence_prefactor=model_flags.sequence_prefactor) + +# Set up the encoder. Here we are using a single unidirectional model. +# To use a bidirectional model as well, call load_model() again with +# configuration.model_config(bidirectional_encoder=True) and paths to the +# bidirectional model's files. The encoder will use the concatenation of +# all loaded models. +encoder = encoder_manager.EncoderManager() +encoder.load_model(model_config=model_config, + vocabulary_file=VOCAB_FILE, + embedding_matrix_file=EMBEDDING_MATRIX_FILE, + checkpoint_path=CHECKPOINT_PATH, + mode='encode-decode') + +# Build the decoder +g = encoder.graph +sess = encoder.sessions[0] + +tensor_names_global = { + 'word_embedding': 'word_embedding:0'} + +tensor_names_pre = { + 'logits': 'logits/logits/decoder_pre:0', + 'decoder_output': 'decoder_pre/decoder_output:0', + 'decoder_state': 'decoder_pre/decoder_state:0'} + +tensor_names_post = { + 'logits': 'logits_1/logits/decoder_post:0', + 'decoder_output': 'decoder_post/decoder_output:0', + 'decoder_state': 'decoder_post/decoder_state:0'} + +decoder_pre = decode.Decoder( + g=g, + tensor_names_decoder=tensor_names_pre, + tensor_names_global=tensor_names_global) + +decoder_post = decode.Decoder( + g=g, + tensor_names_decoder=tensor_names_post, + tensor_names_global=tensor_names_global) + + +# encodings = encoder.encode(data) + + +# Set PATHs +current_path = os.path.dirname(__file__) +PATH_TO_SENTEVAL = os.path.join(current_path, '../') +PATH_TO_DATA = os.path.join(current_path, '../data/senteval_data') + +# import SentEval +sys.path.insert(0, PATH_TO_SENTEVAL) +import senteval + + +# consider the option of lower-casing or not for bow. +def prepare(params, samples): + params.batch_size = 32 + # set to 10 to be comparable to published results + params.kfold = 10 + return + + +def batcher_steps(steps, decoder_type): + def batcher(params, batch): + batch = [" ".join(sent) if sent != [] else " ".join(['.']) + for sent in batch] + + decode_pre_rep, decode_post_rep = decode.decode( + sess=sess, data=batch, + encoder=encoder, + decoder_pre=decoder_pre, + decoder_post=decoder_post, + steps=steps, + use_eos=FLAGS.use_eos) + + decode_rep_concat = np.concatenate( + (np.array(decode_pre_rep), np.array(decode_post_rep)), axis=1) + + if decoder_type == 'mean': + return np.mean(decode_rep_concat, axis=1) + + this_batch_size = len(decode_rep_concat) + return np.reshape(decode_rep_concat, (this_batch_size, -1)) + + return batcher + + +# Set params for SentEval +params_senteval = {'task_path': PATH_TO_DATA, 'usepytorch': False, 'kfold': 10} +params_senteval = dotdict(params_senteval) + +# Set up logger +logging.basicConfig(format='%(asctime)s : %(message)s', level=logging.DEBUG) + +transfer_tasks = [ #'CR', 'MR', 'MPQA', 'SUBJ', 'SST', 'TREC', 'MRPC', + 'SICKRelatedness', 'SICKEntailment'] #, 'STSBenchmark'] + +similarity_tasks = ['STS12', 'STS13', 'STS14', 'STS15', 'STS16'] + +if __name__ == "__main__": + batcher = batcher_steps(steps=FLAGS.unroll_length, + decoder_type=FLAGS.decoder_type) + + se = senteval.SentEval(params_senteval, batcher, prepare) + tasks = transfer_tasks + results = se.eval(tasks) + f = open(FLAGS.output_results_path, 'wb') + cPickle.dump(results, f) + f.close() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..9d9acc8 --- /dev/null +++ b/setup.py @@ -0,0 +1,16 @@ +from setuptools import setup, find_packages + +with open('README.md') as f: + readme = f.read() + +setup( + name='decoding_decoders', + version='0.0.1', + description='Decoding Decoders: Finding Optimal Representation Spaces' + ' for Unsupervised Similarity Tasks', + long_description=readme, + author='Bablyon AI Research', + author_email='nils.hammerla@babylonhealth.com', + url='https://github.com/Babylonpartners/decoding-decoders', + packages=find_packages() +) diff --git a/skip_thoughts/BUILD b/skip_thoughts/BUILD new file mode 100644 index 0000000..40ecd50 --- /dev/null +++ b/skip_thoughts/BUILD @@ -0,0 +1,94 @@ +package(default_visibility = [":internal"]) + +licenses(["notice"]) # Apache 2.0 + +exports_files(["LICENSE"]) + +package_group( + name = "internal", + packages = [ + "//skip_thoughts/...", + ], +) + +py_library( + name = "configuration", + srcs = ["configuration.py"], + srcs_version = "PY2AND3", +) + +py_library( + name = "skip_thoughts_model", + srcs = ["skip_thoughts_model.py"], + srcs_version = "PY2AND3", + deps = [ + "//skip_thoughts/ops:gru_cell", + "//skip_thoughts/ops:input_ops", + ], +) + +py_test( + name = "skip_thoughts_model_test", + size = "large", + srcs = ["skip_thoughts_model_test.py"], + deps = [ + ":configuration", + ":skip_thoughts_model", + ], +) + +py_binary( + name = "train", + srcs = ["train.py"], + srcs_version = "PY2AND3", + deps = [ + ":configuration", + ":skip_thoughts_model", + ], +) + +py_binary( + name = "track_perplexity", + srcs = ["track_perplexity.py"], + srcs_version = "PY2AND3", + deps = [ + ":configuration", + ":skip_thoughts_model", + ], +) + +py_binary( + name = "vocabulary_expansion", + srcs = ["vocabulary_expansion.py"], + srcs_version = "PY2AND3", +) + +py_library( + name = "skip_thoughts_encoder", + srcs = ["skip_thoughts_encoder.py"], + srcs_version = "PY2AND3", + deps = [ + ":skip_thoughts_model", + "//skip_thoughts/data:special_words", + ], +) + +py_library( + name = "encoder_manager", + srcs = ["encoder_manager.py"], + srcs_version = "PY2AND3", + deps = [ + ":skip_thoughts_encoder", + ], +) + +py_binary( + name = "evaluate", + srcs = ["evaluate.py"], + srcs_version = "PY2AND3", + deps = [ + ":encoder_manager", + "//skip_thoughts:configuration", + ], +) + diff --git a/skip_thoughts/README.md b/skip_thoughts/README.md new file mode 100644 index 0000000..96f4e85 --- /dev/null +++ b/skip_thoughts/README.md @@ -0,0 +1,475 @@ +# Skip-Thought Vectors + +This is a TensorFlow implementation of the model described in: + +Jamie Ryan Kiros, Yukun Zhu, Ruslan Salakhutdinov, Richard S. Zemel, +Antonio Torralba, Raquel Urtasun, Sanja Fidler. +[Skip-Thought Vectors](https://papers.nips.cc/paper/5950-skip-thought-vectors.pdf). +*In NIPS, 2015.* + + +## Contact +***Code author:*** Chris Shallue + +***Pull requests and issues:*** @cshallue + +## Contents +* [Model Overview](#model-overview) +* [Getting Started](#getting-started) + * [Install Required Packages](#install-required-packages) + * [Download Pretrained Models (Optional)](#download-pretrained-models-optional) +* [Training a Model](#training-a-model) + * [Prepare the Training Data](#prepare-the-training-data) + * [Run the Training Script](#run-the-training-script) + * [Track Training Progress](#track-training-progress) +* [Expanding the Vocabulary](#expanding-the-vocabulary) + * [Overview](#overview) + * [Preparation](#preparation) + * [Run the Vocabulary Expansion Script](#run-the-vocabulary-expansion-script) +* [Evaluating a Model](#evaluating-a-model) + * [Overview](#overview-1) + * [Preparation](#preparation-1) + * [Run the Evaluation Tasks](#run-the-evaluation-tasks) +* [Encoding Sentences](#encoding-sentences) + +## Model overview + +The *Skip-Thoughts* model is a sentence encoder. It learns to encode input +sentences into a fixed-dimensional vector representation that is useful for many +tasks, for example to detect paraphrases or to classify whether a product review +is positive or negative. See the +[Skip-Thought Vectors](https://papers.nips.cc/paper/5950-skip-thought-vectors.pdf) +paper for details of the model architecture and more example applications. + +A trained *Skip-Thoughts* model will encode similar sentences nearby each other +in the embedding vector space. The following examples show the nearest neighbor by +cosine similarity of some sentences from the +[movie review dataset](https://www.cs.cornell.edu/people/pabo/movie-review-data/). + + +| Input sentence | Nearest Neighbor | +|----------------|------------------| +| Simplistic, silly and tedious. | Trite, banal, cliched, mostly inoffensive. | +| Not so much farcical as sour. | Not only unfunny, but downright repellent. | +| A sensitive and astute first feature by Anne-Sophie Birot. | Absorbing character study by André Turpin . | +| An enthralling, entertaining feature. | A slick, engrossing melodrama. | + +## Getting Started + +### Install Required Packages +First ensure that you have installed the following required packages: + +* **Bazel** ([instructions](http://bazel.build/docs/install.html)) +* **TensorFlow** ([instructions](https://www.tensorflow.org/install/)) +* **NumPy** ([instructions](http://www.scipy.org/install.html)) +* **scikit-learn** ([instructions](http://scikit-learn.org/stable/install.html)) +* **Natural Language Toolkit (NLTK)** + * First install NLTK ([instructions](http://www.nltk.org/install.html)) + * Then install the NLTK data ([instructions](http://www.nltk.org/data.html)) +* **gensim** ([instructions](https://radimrehurek.com/gensim/install.html)) + * Only required if you will be expanding your vocabulary with the [word2vec](https://code.google.com/archive/p/word2vec/) model. + + +### Download Pretrained Models (Optional) + +You can download model checkpoints pretrained on the +[BookCorpus](http://yknzhu.wixsite.com/mbweb) dataset in the following +configurations: + +* Unidirectional RNN encoder ("uni-skip" in the paper) +* Bidirectional RNN encoder ("bi-skip" in the paper) + +```shell +# Directory to download the pretrained models to. +PRETRAINED_MODELS_DIR="${HOME}/skip_thoughts/pretrained/" + +mkdir -p ${PRETRAINED_MODELS_DIR} +cd ${PRETRAINED_MODELS_DIR} + +# Download and extract the unidirectional model. +wget "http://download.tensorflow.org/models/skip_thoughts_uni_2017_02_02.tar.gz" +tar -xvf skip_thoughts_uni_2017_02_02.tar.gz +rm skip_thoughts_uni_2017_02_02.tar.gz + +# Download and extract the bidirectional model. +wget "http://download.tensorflow.org/models/skip_thoughts_bi_2017_02_16.tar.gz" +tar -xvf skip_thoughts_bi_2017_02_16.tar.gz +rm skip_thoughts_bi_2017_02_16.tar.gz +``` + +You can now skip to the sections [Evaluating a Model](#evaluating-a-model) and +[Encoding Sentences](#encoding-sentences). + + +## Training a Model + +### Prepare the Training Data + +To train a model you will need to provide training data in TFRecord format. The +TFRecord format consists of a set of sharded files containing serialized +`tf.Example` protocol buffers. Each `tf.Example` proto contains three +sentences: + + * `encode`: The sentence to encode. + * `decode_pre`: The sentence preceding `encode` in the original text. + * `decode_post`: The sentence following `encode` in the original text. + +Each sentence is a list of words. During preprocessing, a dictionary is created +that assigns each word in the vocabulary to an integer-valued id. Each sentence +is encoded as a list of integer word ids in the `tf.Example` protos. + +We have provided a script to preprocess any set of text-files into this format. +You may wish to use the [BookCorpus](http://yknzhu.wixsite.com/mbweb) dataset. +Note that the preprocessing script may take **12 hours** or more to complete +on this large dataset. + +```shell +# Comma-separated list of globs matching the input input files. The format of +# the input files is assumed to be a list of newline-separated sentences, where +# each sentence is already tokenized. +INPUT_FILES="${HOME}/skip_thoughts/bookcorpus/*.txt" + +# Location to save the preprocessed training and validation data. +DATA_DIR="${HOME}/skip_thoughts/data" + +# Build the preprocessing script. +cd tensorflow-models/skip_thoughts +bazel build -c opt //skip_thoughts/data:preprocess_dataset + +# Run the preprocessing script. +bazel-bin/skip_thoughts/data/preprocess_dataset \ + --input_files=${INPUT_FILES} \ + --output_dir=${DATA_DIR} +``` + +When the script finishes you will find 100 training files and 1 validation file +in `DATA_DIR`. The files will match the patterns `train-?????-of-00100` and +`validation-00000-of-00001` respectively. + +The script will also produce a file named `vocab.txt`. The format of this file +is a list of newline-separated words where the word id is the corresponding 0- +based line index. Words are sorted by descending order of frequency in the input +data. Only the top 20,000 words are assigned unique ids; all other words are +assigned the "unknown id" of 1 in the processed data. + +### Run the Training Script + +Execute the following commands to start the training script. By default it will +run for 500k steps (around 9 days on a GeForce GTX 1080 GPU). + +```shell +# Directory containing the preprocessed data. +DATA_DIR="${HOME}/skip_thoughts/data" + +# Directory to save the model. +MODEL_DIR="${HOME}/skip_thoughts/model" + +# Build the model. +cd tensorflow-models/skip_thoughts +bazel build -c opt //skip_thoughts/... + +# Run the training script. +bazel-bin/skip_thoughts/train \ + --input_file_pattern="${DATA_DIR}/train-?????-of-00100" \ + --train_dir="${MODEL_DIR}/train" +``` + +### Track Training Progress + +Optionally, you can run the `track_perplexity` script in a separate process. +This will log per-word perplexity on the validation set which allows training +progress to be monitored on +[TensorBoard](https://www.tensorflow.org/get_started/summaries_and_tensorboard). + +Note that you may run out of memory if you run the this script on the same GPU +as the training script. You can set the environment variable +`CUDA_VISIBLE_DEVICES=""` to force the script to run on CPU. If it runs too +slowly on CPU, you can decrease the value of `--num_eval_examples`. + +```shell +DATA_DIR="${HOME}/skip_thoughts/data" +MODEL_DIR="${HOME}/skip_thoughts/model" + +# Ignore GPU devices (only necessary if your GPU is currently memory +# constrained, for example, by running the training script). +export CUDA_VISIBLE_DEVICES="" + +# Run the evaluation script. This will run in a loop, periodically loading the +# latest model checkpoint file and computing evaluation metrics. +bazel-bin/skip_thoughts/track_perplexity \ + --input_file_pattern="${DATA_DIR}/validation-?????-of-00001" \ + --checkpoint_dir="${MODEL_DIR}/train" \ + --eval_dir="${MODEL_DIR}/val" \ + --num_eval_examples=50000 +``` + +If you started the `track_perplexity` script, run a +[TensorBoard](https://www.tensorflow.org/get_started/summaries_and_tensorboard) +server in a separate process for real-time monitoring of training summaries and +validation perplexity. + +```shell +MODEL_DIR="${HOME}/skip_thoughts/model" + +# Run a TensorBoard server. +tensorboard --logdir="${MODEL_DIR}" +``` + +## Expanding the Vocabulary + +### Overview + +The vocabulary generated by the preprocessing script contains only 20,000 words +which is insufficient for many tasks. For example, a sentence from Wikipedia +might contain nouns that do not appear in this vocabulary. + +A solution to this problem described in the +[Skip-Thought Vectors](https://papers.nips.cc/paper/5950-skip-thought-vectors.pdf) +paper is to learn a mapping that transfers word representations from one model to +another. This idea is based on the "Translation Matrix" method from the paper +[Exploiting Similarities Among Languages for Machine Translation](https://arxiv.org/abs/1309.4168). + + +Specifically, we will load the word embeddings from a trained *Skip-Thoughts* +model and from a trained [word2vec model](https://arxiv.org/pdf/1301.3781.pdf) +(which has a much larger vocabulary). We will train a linear regression model +without regularization to learn a linear mapping from the word2vec embedding +space to the *Skip-Thoughts* embedding space. We will then apply the linear +model to all words in the word2vec vocabulary, yielding vectors in the *Skip- +Thoughts* word embedding space for the union of the two vocabularies. + +The linear regression task is to learn a parameter matrix *W* to minimize +*|| X - Y \* W ||2*, where *X* is a matrix of *Skip-Thoughts* +embeddings of shape `[num_words, dim1]`, *Y* is a matrix of word2vec embeddings +of shape `[num_words, dim2]`, and *W* is a matrix of shape `[dim2, dim1]`. + +### Preparation + +First you will need to download and unpack a pretrained +[word2vec model](https://arxiv.org/pdf/1301.3781.pdf) from +[this website](https://code.google.com/archive/p/word2vec/) +([direct download link](https://drive.google.com/file/d/0B7XkCwpI5KDYNlNUTTlSS21pQmM/edit?usp=sharing)). +This model was trained on the Google News dataset (about 100 billion words). + + +Also ensure that you have already [installed gensim](https://radimrehurek.com/gensim/install.html). + +### Run the Vocabulary Expansion Script + +```shell +# Path to checkpoint file or a directory containing checkpoint files (the script +# will select the most recent). +CHECKPOINT_PATH="${HOME}/skip_thoughts/model/train" + +# Vocabulary file generated by the preprocessing script. +SKIP_THOUGHTS_VOCAB="${HOME}/skip_thoughts/data/vocab.txt" + +# Path to downloaded word2vec model. +WORD2VEC_MODEL="${HOME}/skip_thoughts/googlenews/GoogleNews-vectors-negative300.bin" + +# Output directory. +EXP_VOCAB_DIR="${HOME}/skip_thoughts/exp_vocab" + +# Build the vocabulary expansion script. +cd tensorflow-models/skip_thoughts +bazel build -c opt //skip_thoughts:vocabulary_expansion + +# Run the vocabulary expansion script. +bazel-bin/skip_thoughts/vocabulary_expansion \ + --skip_thoughts_model=${CHECKPOINT_PATH} \ + --skip_thoughts_vocab=${SKIP_THOUGHTS_VOCAB} \ + --word2vec_model=${WORD2VEC_MODEL} \ + --output_dir=${EXP_VOCAB_DIR} +``` + +## Evaluating a Model + +### Overview + +The model can be evaluated using the benchmark tasks described in the +[Skip-Thought Vectors](https://papers.nips.cc/paper/5950-skip-thought-vectors.pdf) +paper. The following tasks are supported (refer to the paper for full details): + + * **SICK** semantic relatedness task. + * **MSRP** (Microsoft Research Paraphrase Corpus) paraphrase detection task. + * Binary classification tasks: + * **MR** movie review sentiment task. + * **CR** customer product review task. + * **SUBJ** subjectivity/objectivity task. + * **MPQA** opinion polarity task. + * **TREC** question-type classification task. + +### Preparation + +You will need to clone or download the +[skip-thoughts GitHub repository](https://github.com/ryankiros/skip-thoughts) by +[ryankiros](https://github.com/ryankiros) (the first author of the Skip-Thoughts +paper): + +```shell +# Folder to clone the repository to. +ST_KIROS_DIR="${HOME}/skip_thoughts/skipthoughts_kiros" + +# Clone the repository. +git clone git@github.com:ryankiros/skip-thoughts.git "${ST_KIROS_DIR}/skipthoughts" + +# Make the package importable. +export PYTHONPATH="${ST_KIROS_DIR}/:${PYTHONPATH}" +``` + +You will also need to download the data needed for each evaluation task. See the +instructions [here](https://github.com/ryankiros/skip-thoughts). + +For example, the CR (customer review) dataset is found [here](http://nlp.stanford.edu/~sidaw/home/projects:nbsvm). For this task we want the +files `custrev.pos` and `custrev.neg`. + +### Run the Evaluation Tasks + +In the following example we will evaluate a unidirectional model ("uni-skip" in +the paper) on the CR task. To use a bidirectional model ("bi-skip" in the +paper), simply pass the flags `--bi_vocab_file`, `--bi_embeddings_file` and +`--bi_checkpoint_path` instead. To use the "combine-skip" model described in the +paper you will need to pass both the unidirectional and bidirectional flags. + +```shell +# Path to checkpoint file or a directory containing checkpoint files (the script +# will select the most recent). +CHECKPOINT_PATH="${HOME}/skip_thoughts/model/train" + +# Vocabulary file generated by the vocabulary expansion script. +VOCAB_FILE="${HOME}/skip_thoughts/exp_vocab/vocab.txt" + +# Embeddings file generated by the vocabulary expansion script. +EMBEDDINGS_FILE="${HOME}/skip_thoughts/exp_vocab/embeddings.npy" + +# Directory containing files custrev.pos and custrev.neg. +EVAL_DATA_DIR="${HOME}/skip_thoughts/eval_data" + +# Build the evaluation script. +cd tensorflow-models/skip_thoughts +bazel build -c opt //skip_thoughts:evaluate + +# Run the evaluation script. +bazel-bin/skip_thoughts/evaluate \ + --eval_task=CR \ + --data_dir=${EVAL_DATA_DIR} \ + --uni_vocab_file=${VOCAB_FILE} \ + --uni_embeddings_file=${EMBEDDINGS_FILE} \ + --uni_checkpoint_path=${CHECKPOINT_PATH} +``` + +Output: + +```python +[0.82539682539682535, 0.84084880636604775, 0.83023872679045096, + 0.86206896551724133, 0.83554376657824936, 0.85676392572944293, + 0.84084880636604775, 0.83023872679045096, 0.85145888594164454, + 0.82758620689655171] +``` + +The output is a list of accuracies of 10 cross-validation classification models. +To get a single number, simply take the average: + +```python +ipython # Launch iPython. + +In [0]: +import numpy as np +np.mean([0.82539682539682535, 0.84084880636604775, 0.83023872679045096, + 0.86206896551724133, 0.83554376657824936, 0.85676392572944293, + 0.84084880636604775, 0.83023872679045096, 0.85145888594164454, + 0.82758620689655171]) + +Out [0]: 0.84009936423729525 +``` + +## Encoding Sentences + +In this example we will encode data from the +[movie review dataset](https://www.cs.cornell.edu/people/pabo/movie-review-data/) +(specifically the [sentence polarity dataset v1.0](https://www.cs.cornell.edu/people/pabo/movie-review-data/rt-polaritydata.tar.gz)). + +```python +ipython # Launch iPython. + +In [0]: + +# Imports. +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +import numpy as np +import os.path +import scipy.spatial.distance as sd +from skip_thoughts import configuration +from skip_thoughts import encoder_manager + +In [1]: +# Set paths to the model. +VOCAB_FILE = "/path/to/vocab.txt" +EMBEDDING_MATRIX_FILE = "/path/to/embeddings.npy" +CHECKPOINT_PATH = "/path/to/model.ckpt-9999" +# The following directory should contain files rt-polarity.neg and +# rt-polarity.pos. +MR_DATA_DIR = "/dir/containing/mr/data" + +In [2]: +# Set up the encoder. Here we are using a single unidirectional model. +# To use a bidirectional model as well, call load_model() again with +# configuration.model_config(bidirectional_encoder=True) and paths to the +# bidirectional model's files. The encoder will use the concatenation of +# all loaded models. +encoder = encoder_manager.EncoderManager() +encoder.load_model(configuration.model_config(), + vocabulary_file=VOCAB_FILE, + embedding_matrix_file=EMBEDDING_MATRIX_FILE, + checkpoint_path=CHECKPOINT_PATH) + +In [3]: +# Load the movie review dataset. +data = [] +with open(os.path.join(MR_DATA_DIR, 'rt-polarity.neg'), 'rb') as f: + data.extend([line.decode('latin-1').strip() for line in f]) +with open(os.path.join(MR_DATA_DIR, 'rt-polarity.pos'), 'rb') as f: + data.extend([line.decode('latin-1').strip() for line in f]) + +In [4]: +# Generate Skip-Thought Vectors for each sentence in the dataset. +encodings = encoder.encode(data) + +In [5]: +# Define a helper function to generate nearest neighbors. +def get_nn(ind, num=10): + encoding = encodings[ind] + scores = sd.cdist([encoding], encodings, "cosine")[0] + sorted_ids = np.argsort(scores) + print("Sentence:") + print("", data[ind]) + print("\nNearest neighbors:") + for i in range(1, num + 1): + print(" %d. %s (%.3f)" % + (i, data[sorted_ids[i]], scores[sorted_ids[i]])) + +In [6]: +# Compute nearest neighbors of the first sentence in the dataset. +get_nn(0) +``` + +Output: + +``` +Sentence: + simplistic , silly and tedious . + +Nearest neighbors: + 1. trite , banal , cliched , mostly inoffensive . (0.247) + 2. banal and predictable . (0.253) + 3. witless , pointless , tasteless and idiotic . (0.272) + 4. loud , silly , stupid and pointless . (0.295) + 5. grating and tedious . (0.299) + 6. idiotic and ugly . (0.330) + 7. black-and-white and unrealistic . (0.335) + 8. hopelessly inane , humorless and under-inspired . (0.335) + 9. shallow , noisy and pretentious . (0.340) + 10. . . . unlikable , uninteresting , unfunny , and completely , utterly inept . (0.346) +``` \ No newline at end of file diff --git a/skip_thoughts/__init__.py b/skip_thoughts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/skip_thoughts/configuration.py b/skip_thoughts/configuration.py new file mode 100644 index 0000000..db76406 --- /dev/null +++ b/skip_thoughts/configuration.py @@ -0,0 +1,146 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Changes by Babylon Partners +# - Added decoder configs +# - Added pretrained embeddings configs +# ============================================================================== +"""Default configuration for model architecture and training.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +class _HParams(object): + """Wrapper for configuration parameters.""" + pass + + +def model_config(input_file_pattern=None, + input_queue_capacity=640000, + num_input_reader_threads=1, + shuffle_input_data=True, + uniform_init_scale=0.1, + vocab_size=20000, + batch_size=128, + word_embedding_dim=620, + pretrained_word_emb_file=None, + word_emb_trainable=False, + bidirectional_encoder=False, + encoder_dim=2400, + skipgram_encoder=False, + sequence_decoder_pre=True, + sequence_decoder_cur=False, + sequence_decoder_post=True, + skipgram_decoder_pre=True, + skipgram_decoder_cur=False, + skipgram_decoder_post=True, + share_weights_logits=True, + normalise_decoder_losses=False, + skipgram_prefactor=1., + sequence_prefactor=1.): + """Creates a model configuration object. + + Args: + input_file_pattern: File pattern of sharded TFRecord files containing + tf.Example protobufs. + input_queue_capacity: Number of examples to keep in the input queue. + num_input_reader_threads: Number of threads for prefetching input + tf.Examples. + shuffle_input_data: Whether to shuffle the input data. + uniform_init_scale: Scale of random uniform initializer. + vocab_size: Number of unique words in the vocab. + batch_size: Batch size (training and evaluation only). + word_embedding_dim: Word embedding dimension. + bidirectional_encoder: Whether to use a bidirectional or unidirectional + encoder RNN. + encoder_dim: Number of output dimensions of the sentence encoder. + + Returns: + An object containing model configuration parameters. + """ + config = _HParams() + config.input_file_pattern = input_file_pattern + config.input_queue_capacity = input_queue_capacity + config.num_input_reader_threads = num_input_reader_threads + config.shuffle_input_data = shuffle_input_data + config.uniform_init_scale = uniform_init_scale + config.vocab_size = vocab_size + config.batch_size = batch_size + config.word_embedding_dim = word_embedding_dim + config.pretrained_word_emb_file = pretrained_word_emb_file + config.word_emb_trainable = word_emb_trainable + config.bidirectional_encoder = bidirectional_encoder + config.encoder_dim = encoder_dim + config.skipgram_encoder = skipgram_encoder + config.sequence_decoder_pre = sequence_decoder_pre + config.sequence_decoder_cur = sequence_decoder_cur + config.sequence_decoder_post = sequence_decoder_post + config.skipgram_decoder_pre = skipgram_decoder_pre + config.skipgram_decoder_cur = skipgram_decoder_cur + config.skipgram_decoder_post = skipgram_decoder_post + config.share_weights_logits = share_weights_logits + config.normalise_decoder_losses = normalise_decoder_losses + config.skipgram_prefactor = skipgram_prefactor + config.sequence_prefactor = sequence_prefactor + config.num_skipgram_decoders = sum((config.skipgram_decoder_pre, + config.skipgram_decoder_cur, + config.skipgram_decoder_post)) + config.num_sequence_decoders = sum((config.sequence_decoder_pre, + config.sequence_decoder_cur, + config.sequence_decoder_post)) + return config + + +def training_config(learning_rate=0.0008, + learning_rate_decay_factor=0.5, + learning_rate_decay_steps=400000, + number_of_steps=500000, + clip_gradient_norm=5.0, + save_model_secs=600, + save_summaries_secs=600): + """Creates a training configuration object. + + Args: + learning_rate: Initial learning rate. + learning_rate_decay_factor: If > 0, the learning rate decay factor. + learning_rate_decay_steps: The number of steps before the learning rate + decays by learning_rate_decay_factor. + number_of_steps: The total number of training steps to run. Passing None + will cause the training script to run indefinitely. + clip_gradient_norm: If not None, then clip gradients to this value. + save_model_secs: How often (in seconds) to save model checkpoints. + save_summaries_secs: How often (in seconds) to save model summaries. + + Returns: + An object containing training configuration parameters. + + Raises: + ValueError: If learning_rate_decay_factor is set and + learning_rate_decay_steps is unset. + """ + if learning_rate_decay_factor and not learning_rate_decay_steps: + raise ValueError( + "learning_rate_decay_factor requires learning_rate_decay_steps.") + + config = _HParams() + config.learning_rate = learning_rate + config.learning_rate_decay_factor = learning_rate_decay_factor + config.learning_rate_decay_steps = learning_rate_decay_steps + config.number_of_steps = number_of_steps + config.clip_gradient_norm = clip_gradient_norm + config.save_model_secs = save_model_secs + config.save_summaries_secs = save_summaries_secs + return config diff --git a/skip_thoughts/data/BUILD b/skip_thoughts/data/BUILD new file mode 100644 index 0000000..afc209e --- /dev/null +++ b/skip_thoughts/data/BUILD @@ -0,0 +1,23 @@ +package(default_visibility = ["//skip_thoughts:internal"]) + +licenses(["notice"]) # Apache 2.0 + +exports_files(["LICENSE"]) + +py_library( + name = "special_words", + srcs = ["special_words.py"], + srcs_version = "PY2AND3", + deps = [], +) + +py_binary( + name = "preprocess_dataset", + srcs = [ + "preprocess_dataset.py", + ], + srcs_version = "PY2AND3", + deps = [ + ":special_words", + ], +) diff --git a/skip_thoughts/data/__init__.py b/skip_thoughts/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/skip_thoughts/data/preprocess_dataset.py b/skip_thoughts/data/preprocess_dataset.py new file mode 100644 index 0000000..5764306 --- /dev/null +++ b/skip_thoughts/data/preprocess_dataset.py @@ -0,0 +1,308 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Changes by Babylon Partners +# - Added _string_to_words +# ============================================================================== +"""Converts a set of text files to TFRecord format with Example protos. + +Each Example proto in the output contains the following fields: + + decode_pre: list of int64 ids corresponding to the "previous" sentence. + encode: list of int64 ids corresponding to the "current" sentence. + decode_post: list of int64 ids corresponding to the "post" sentence. + +In addition, the following files are generated: + + vocab.txt: List of " " pairs, where is the integer + encoding of in the Example protos. + word_counts.txt: List of " " pairs, where is the number + of occurrences of in the input files. + +The vocabulary of word ids is constructed from the top --num_words by word +count. All other words get the word id. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections +import os + + +import numpy as np +import tensorflow as tf + +from skip_thoughts.data import special_words + +FLAGS = tf.flags.FLAGS + +tf.flags.DEFINE_string("input_files", None, + "Comma-separated list of globs matching the input " + "files. The format of the input files is assumed to be " + "a list of newline-separated sentences, where each " + "sentence is already tokenized.") + +tf.flags.DEFINE_string("vocab_file", "", + "(Optional) existing vocab file. Otherwise, a new vocab " + "file is created and written to the output directory. " + "The file format is a list of newline-separated words, " + "where the word id is the corresponding 0-based index " + "in the file.") + +tf.flags.DEFINE_string("output_dir", None, "Output directory.") + +tf.flags.DEFINE_integer("train_output_shards", 100, + "Number of output shards for the training set.") + +tf.flags.DEFINE_integer("validation_output_shards", 1, + "Number of output shards for the validation set.") + +tf.flags.DEFINE_integer("num_validation_sentences", 50000, + "Number of output shards for the validation set.") + +tf.flags.DEFINE_integer("num_words", 20000, + "Number of words to include in the output.") + +tf.flags.DEFINE_integer("max_sentences", 0, + "If > 0, the maximum number of sentences to output.") + +tf.flags.DEFINE_integer("max_sentence_length", 30, + "If > 0, exclude sentences whose encode, decode_pre OR" + "decode_post sentence exceeds this length.") + +tf.flags.DEFINE_boolean("add_eos", True, + "Whether to add end-of-sentence ids to the output.") + +tf.logging.set_verbosity(tf.logging.INFO) + + +def _string_to_words(sentence): + return [w.strip() for w in sentence.split()] + + +def _build_vocabulary(input_files): + """Loads or builds the model vocabulary. + + Args: + input_files: List of pre-tokenized input .txt files. + + Returns: + vocab: A dictionary of word to id. + """ + if FLAGS.vocab_file: + tf.logging.info("Loading existing vocab file.") + vocab = collections.OrderedDict() + with tf.gfile.GFile(FLAGS.vocab_file, mode="r") as f: + for i, line in enumerate(f): + word = line.decode("utf-8").strip() + assert word not in vocab, "Attempting to add word twice: %s" % word + vocab[word] = i + tf.logging.info("Read vocab of size %d from %s", + len(vocab), FLAGS.vocab_file) + return vocab + + tf.logging.info("Creating vocabulary.") + num = 0 + wordcount = collections.Counter() + for input_file in input_files: + tf.logging.info("Processing file: %s", input_file) + for sentence in tf.gfile.FastGFile(input_file): + wordcount.update(_string_to_words(sentence)) + + num += 1 + if num % 1000000 == 0: + tf.logging.info("Processed %d sentences", num) + + tf.logging.info("Processed %d sentences total", num) + + words = wordcount.keys() + freqs = wordcount.values() + sorted_indices = np.argsort(freqs)[::-1] + + vocab = collections.OrderedDict() + vocab[special_words.EOS] = special_words.EOS_ID + vocab[special_words.UNK] = special_words.UNK_ID + for w_id, w_index in enumerate(sorted_indices[0:FLAGS.num_words - 2]): + vocab[words[w_index]] = w_id + 2 # 0: EOS, 1: UNK. + + tf.logging.info("Created vocab with %d words", len(vocab)) + + vocab_file = os.path.join(FLAGS.output_dir, "vocab.txt") + with tf.gfile.FastGFile(vocab_file, "w") as f: + f.write("\n".join(vocab.keys())) + tf.logging.info("Wrote vocab file to %s", vocab_file) + + word_counts_file = os.path.join(FLAGS.output_dir, "word_counts.txt") + with tf.gfile.FastGFile(word_counts_file, "w") as f: + for i in sorted_indices: + f.write("%s %d\n" % (words[i], freqs[i])) + tf.logging.info("Wrote word counts file to %s", word_counts_file) + + return vocab + + +def _int64_feature(value): + """Helper for creating an Int64 Feature.""" + return tf.train.Feature(int64_list=tf.train.Int64List( + value=[int(v) for v in value])) + + +def _sentence_to_ids(sentence, vocab): + """Helper for converting a sentence (list of words) to a list of ids.""" + ids = [vocab.get(w, special_words.UNK_ID) for w in sentence] + if FLAGS.add_eos: + ids.append(special_words.EOS_ID) + return ids + + +def _create_serialized_example(predecessor, current, successor, vocab): + """Helper for creating a serialized Example proto.""" + example = tf.train.Example(features=tf.train.Features(feature={ + "decode_pre": _int64_feature(_sentence_to_ids(predecessor, vocab)), + "encode": _int64_feature(_sentence_to_ids(current, vocab)), + "decode_post": _int64_feature(_sentence_to_ids(successor, vocab)), + })) + + return example.SerializeToString() + + +def _process_input_file(filename, vocab, stats): + """Processes the sentences in an input file. + + Args: + filename: Path to a pre-tokenized input .txt file. + vocab: A dictionary of word to id. + stats: A Counter object for statistics. + + Returns: + processed: A list of serialized Example protos + """ + tf.logging.info("Processing input file: %s", filename) + processed = [] + + predecessor = None # Predecessor sentence (list of words). + current = None # Current sentence (list of words). + successor = None # Successor sentence (list of words). + + for successor_str in tf.gfile.FastGFile(filename): + stats.update(["sentences_seen"]) + successor = _string_to_words(successor_str) + + # The first 2 sentences per file will be skipped. + if predecessor and current and successor: + stats.update(["sentences_considered"]) + + # Note that we are going to insert later, so we only allow + # sentences with strictly less than max_sentence_length to pass. + if FLAGS.max_sentence_length and ( + len(predecessor) >= FLAGS.max_sentence_length or len(current) >= + FLAGS.max_sentence_length or len(successor) >= + FLAGS.max_sentence_length): + stats.update(["sentences_too_long"]) + else: + serialized = _create_serialized_example(predecessor, current, successor, + vocab) + processed.append(serialized) + stats.update(["sentences_output"]) + + predecessor = current + current = successor + + sentences_seen = stats["sentences_seen"] + sentences_output = stats["sentences_output"] + if sentences_seen and sentences_seen % 100000 == 0: + tf.logging.info("Processed %d sentences (%d output)", sentences_seen, + sentences_output) + if FLAGS.max_sentences and sentences_output >= FLAGS.max_sentences: + break + + tf.logging.info("Completed processing file %s", filename) + return processed + + +def _write_shard(filename, dataset, indices): + """Writes a TFRecord shard.""" + with tf.python_io.TFRecordWriter(filename) as writer: + for j in indices: + writer.write(dataset[j]) + + +def _write_dataset(name, dataset, indices, num_shards): + """Writes a sharded TFRecord dataset. + + Args: + name: Name of the dataset (e.g. "train"). + dataset: List of serialized Example protos. + indices: List of indices of 'dataset' to be written. + num_shards: The number of output shards. + """ + tf.logging.info("Writing dataset %s", name) + borders = np.int32(np.linspace(0, len(indices), num_shards + 1)) + for i in range(num_shards): + filename = os.path.join(FLAGS.output_dir, "%s-%.5d-of-%.5d" % (name, i, + num_shards)) + shard_indices = indices[borders[i]:borders[i + 1]] + _write_shard(filename, dataset, shard_indices) + tf.logging.info("Wrote dataset indices [%d, %d) to output shard %s", + borders[i], borders[i + 1], filename) + tf.logging.info("Finished writing %d sentences in dataset %s.", + len(indices), name) + + +def main(unused_argv): + if not FLAGS.input_files: + raise ValueError("--input_files is required.") + if not FLAGS.output_dir: + raise ValueError("--output_dir is required.") + + if not tf.gfile.IsDirectory(FLAGS.output_dir): + tf.gfile.MakeDirs(FLAGS.output_dir) + + input_files = [] + for pattern in FLAGS.input_files.split(","): + match = tf.gfile.Glob(FLAGS.input_files) + if not match: + raise ValueError("Found no files matching %s" % pattern) + input_files.extend(match) + tf.logging.info("Found %d input files.", len(input_files)) + + vocab = _build_vocabulary(input_files) + + tf.logging.info("Generating dataset.") + stats = collections.Counter() + dataset = [] + for filename in input_files: + dataset.extend(_process_input_file(filename, vocab, stats)) + if FLAGS.max_sentences and stats["sentences_output"] >= FLAGS.max_sentences: + break + + tf.logging.info("Generated dataset with %d sentences.", len(dataset)) + for k, v in stats.items(): + tf.logging.info("%s: %d", k, v) + + tf.logging.info("Shuffling dataset.") + np.random.seed(123) + shuffled_indices = np.random.permutation(len(dataset)) + val_indices = shuffled_indices[:FLAGS.num_validation_sentences] + train_indices = shuffled_indices[FLAGS.num_validation_sentences:] + + _write_dataset("train", dataset, train_indices, FLAGS.train_output_shards) + _write_dataset("validation", dataset, val_indices, + FLAGS.validation_output_shards) + + +if __name__ == "__main__": + tf.app.run() diff --git a/skip_thoughts/data/special_words.py b/skip_thoughts/data/special_words.py new file mode 100644 index 0000000..fb76b7a --- /dev/null +++ b/skip_thoughts/data/special_words.py @@ -0,0 +1,27 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Special word constants. + +NOTE: The ids of the EOS and UNK constants should not be modified. It is assumed +that these always occupy the first two ids. +""" + +# End of sentence. +EOS = "" +EOS_ID = 0 + +# Unknown. +UNK = "" +UNK_ID = 1 diff --git a/skip_thoughts/decode.py b/skip_thoughts/decode.py new file mode 100644 index 0000000..b7bcf10 --- /dev/null +++ b/skip_thoughts/decode.py @@ -0,0 +1,161 @@ +# Copyright 2018 Babylon Partners. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import numpy as np +import tensorflow as tf + +from skip_thoughts import skip_thoughts_encoder + + +class Decoder: + def __init__( + self, + g, + tensor_names_decoder, + tensor_names_global): + self.g = g + self.tensors_decoder = _names_to_tensors( + g=self.g, x=tensor_names_decoder) + self.tensors_global = _names_to_tensors( + g=self.g, x=tensor_names_global) + + self.state = self.tensors_decoder['decoder_state'] + + self.embedding_dim = tf.shape( + self.tensors_global['word_embedding'])[-1] + + self.batch_size, self.decoder_seq_len = _get_batch_seq_len( + self.tensors_decoder['decoder_output']) + + self.softmax_flat = tf.nn.softmax( + logits=self.tensors_decoder['logits']) + + self.softmax_w_flat = tf.matmul( + self.softmax_flat, self.tensors_global['word_embedding']) + + self.softmax_w = tf.reshape( + self.softmax_w_flat, + (self.batch_size, self.decoder_seq_len, self.embedding_dim)) + + +def _is_tensor_name(x): + if ":" in x: + return True + return False + + +def _get_tensor_or_op(g, x): + if _is_tensor_name(x): + return g.get_tensor_by_name(x) + + return g.get_operation_by_name(x) + + +def _get_batch_seq_len(x): + x_sh = tf.shape(x) + return x_sh[0], x_sh[1] + + +def _names_to_tensors(g, x): + return {k: _get_tensor_or_op(g, v) for k, v in x.iteritems()} + + +def unroll_decoder( + sess, + encoder_embeddings, + encoder_mask, + decoder_name, + decoder_softmax_w_embs, + decoder_state, + steps=5): + n_input_sequences = encoder_embeddings.shape[0] + sequence_dim = encoder_embeddings.shape[2] + start_tokens = np.zeros(shape=(n_input_sequences, 1, sequence_dim)) + decoder_input = start_tokens + feed_dict = { + "encode_emb:0": encoder_embeddings, + "encode_mask:0": encoder_mask} + dec_emb_feed = "{decoder_name}_emb:0".format(decoder_name=decoder_name) + dec_mask_feed = "{decoder_name}_mask:0".format(decoder_name=decoder_name) + all_states = None + + for _ in range(steps): + len_seq = decoder_input.shape[1] + decode_mask = np.ones((n_input_sequences, len_seq)) + feed_dict.update({dec_emb_feed: decoder_input, + dec_mask_feed: decode_mask}) + softmax_w_embs, states = sess.run( + (decoder_softmax_w_embs, decoder_state), + feed_dict=feed_dict) + states_expanded = np.expand_dims(states, axis=1) + if all_states is None: + all_states = states_expanded + else: + all_states = np.concatenate((all_states, states_expanded), axis=1) + decoder_input = np.concatenate((start_tokens, softmax_w_embs), axis=1) + return all_states + + +def decode(sess, + data, + encoder, + decoder_pre, + decoder_post, + use_norm=True, + verbose=True, + batch_size=128, + use_eos=False, + steps=5): + data = encoder.encoders[0]._preprocess(data=data, use_eos=use_eos) + + pre_states = [] + post_states = [] + + batch_indices = np.arange(0, len(data), batch_size) + for batch, start_index in enumerate(batch_indices): + if verbose: + tf.logging.info("Batch %d / %d.", batch, len(batch_indices)) + + (encoder_embeddings, + encoder_mask) = skip_thoughts_encoder._batch_and_pad( + data[start_index:start_index + batch_size]) + + pre_states.extend(unroll_decoder( + sess=sess, + encoder_embeddings=encoder_embeddings, + encoder_mask=encoder_mask, + decoder_name='decode_pre', + decoder_softmax_w_embs=decoder_pre.softmax_w, + decoder_state=decoder_pre.state, + steps=steps)) + + post_states.extend(unroll_decoder( + sess=sess, + encoder_embeddings=encoder_embeddings, + encoder_mask=encoder_mask, + decoder_name='decode_post', + decoder_softmax_w_embs=decoder_post.softmax_w, + decoder_state=decoder_post.state, + steps=steps)) + + if use_norm: + pre_states = [v / np.linalg.norm(v) for v in pre_states] + post_states = [v / np.linalg.norm(v) for v in post_states] + + return pre_states, post_states diff --git a/skip_thoughts/encoder_manager.py b/skip_thoughts/encoder_manager.py new file mode 100644 index 0000000..55ae264 --- /dev/null +++ b/skip_thoughts/encoder_manager.py @@ -0,0 +1,140 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Changes by Babylon Partners +# - Added new encode-decode mode +# ============================================================================== +"""Manager class for loading and encoding with multiple skip-thoughts models. + +If multiple models are loaded at once then the encode() function returns the +concatenation of the outputs of each model. + +Example usage: + manager = EncoderManager() + manager.load_model(model_config_1, vocabulary_file_1, embedding_matrix_file_1, + checkpoint_path_1) + manager.load_model(model_config_2, vocabulary_file_2, embedding_matrix_file_2, + checkpoint_path_2) + encodings = manager.encode(data) +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections + + +import numpy as np +import tensorflow as tf + +from skip_thoughts import skip_thoughts_encoder + + +class EncoderManager(object): + """Manager class for loading and encoding with skip-thoughts models.""" + + def __init__(self): + self.encoders = [] + self.sessions = [] + self.graph = None + + def load_model(self, model_config, vocabulary_file, embedding_matrix_file, + checkpoint_path, mode='encode'): + """Loads a skip-thoughts model. + + Args: + model_config: Object containing parameters for building the model. + vocabulary_file: Path to vocabulary file containing a list of newline- + separated words where the word id is the corresponding 0-based index in + the file. + embedding_matrix_file: Path to a serialized numpy array of shape + [vocab_size, embedding_dim]. + checkpoint_path: SkipThoughtsModel checkpoint file or a directory + containing a checkpoint file. + """ + tf.logging.info("Reading vocabulary from %s", vocabulary_file) + with tf.gfile.GFile(vocabulary_file, mode="r") as f: + lines = list(f.readlines()) + reverse_vocab = [line.decode("utf-8").strip() for line in lines] + tf.logging.info("Loaded vocabulary with %d words.", len(reverse_vocab)) + + tf.logging.info("Loading embedding matrix from %s", embedding_matrix_file) + # Note: tf.gfile.GFile doesn't work here because np.load() calls f.seek() + # with 3 arguments. + with open(embedding_matrix_file, "r") as f: + embedding_matrix = np.load(f) + tf.logging.info("Loaded embedding matrix with shape %s", + embedding_matrix.shape) + + word_embeddings = collections.OrderedDict( + zip(reverse_vocab, embedding_matrix)) + + g = tf.Graph() + with g.as_default(): + encoder = skip_thoughts_encoder.SkipThoughtsEncoder(word_embeddings) + restore_model = encoder.build_graph_from_config(model_config, + checkpoint_path, + mode=mode) + + self.graph = g + sess = tf.Session(graph=g) + restore_model(sess) + + self.encoders.append(encoder) + self.sessions.append(sess) + + def encode(self, + data, + use_norm=True, + verbose=False, + batch_size=128, + use_eos=False): + """Encodes a sequence of sentences as skip-thought vectors. + + Args: + data: A list of input strings. + use_norm: If True, normalize output skip-thought vectors to unit L2 norm. + verbose: Whether to log every batch. + batch_size: Batch size for the RNN encoders. + use_eos: If True, append the end-of-sentence word to each input sentence. + + Returns: + thought_vectors: A list of numpy arrays corresponding to 'data'. + + Raises: + ValueError: If called before calling load_encoder. + """ + if not self.encoders: + raise ValueError( + "Must call load_model at least once before calling encode.") + + encoded = [] + for encoder, sess in zip(self.encoders, self.sessions): + encoded.append( + np.array( + encoder.encode( + sess, + data, + use_norm=use_norm, + verbose=verbose, + batch_size=batch_size, + use_eos=use_eos))) + + return np.concatenate(encoded, axis=1) + + def close(self): + """Closes the active TensorFlow Sessions.""" + for sess in self.sessions: + sess.close() diff --git a/skip_thoughts/evaluate.py b/skip_thoughts/evaluate.py new file mode 100644 index 0000000..e840d9d --- /dev/null +++ b/skip_thoughts/evaluate.py @@ -0,0 +1,117 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Script to evaluate a skip-thoughts model. + +This script can evaluate a model with a unidirectional encoder ("uni-skip" in +the paper); or a model with a bidirectional encoder ("bi-skip"); or the +combination of a model with a unidirectional encoder and a model with a +bidirectional encoder ("combine-skip"). + +The uni-skip model (if it exists) is specified by the flags +--uni_vocab_file, --uni_embeddings_file, --uni_checkpoint_path. + +The bi-skip model (if it exists) is specified by the flags +--bi_vocab_file, --bi_embeddings_path, --bi_checkpoint_path. + +The evaluation tasks have different running times. SICK may take 5-10 minutes. +MSRP, TREC and CR may take 20-60 minutes. SUBJ, MPQA and MR may take 2+ hours. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +from skipthoughts import eval_classification +from skipthoughts import eval_msrp +from skipthoughts import eval_sick +from skipthoughts import eval_trec +import tensorflow as tf + +from skip_thoughts import configuration +from skip_thoughts import encoder_manager + +FLAGS = tf.flags.FLAGS + +tf.flags.DEFINE_string("eval_task", "CR", + "Name of the evaluation task to run. Available tasks: " + "MR, CR, SUBJ, MPQA, SICK, MSRP, TREC.") + +tf.flags.DEFINE_string("data_dir", None, "Directory containing training data.") + +tf.flags.DEFINE_string("uni_vocab_file", None, + "Path to vocabulary file containing a list of newline-" + "separated words where the word id is the " + "corresponding 0-based index in the file.") +tf.flags.DEFINE_string("bi_vocab_file", None, + "Path to vocabulary file containing a list of newline-" + "separated words where the word id is the " + "corresponding 0-based index in the file.") + +tf.flags.DEFINE_string("uni_embeddings_file", None, + "Path to serialized numpy array of shape " + "[vocab_size, embedding_dim].") +tf.flags.DEFINE_string("bi_embeddings_file", None, + "Path to serialized numpy array of shape " + "[vocab_size, embedding_dim].") + +tf.flags.DEFINE_string("uni_checkpoint_path", None, + "Checkpoint file or directory containing a checkpoint " + "file.") +tf.flags.DEFINE_string("bi_checkpoint_path", None, + "Checkpoint file or directory containing a checkpoint " + "file.") + +tf.logging.set_verbosity(tf.logging.INFO) + + +def main(unused_argv): + if not FLAGS.data_dir: + raise ValueError("--data_dir is required.") + + encoder = encoder_manager.EncoderManager() + + # Maybe load unidirectional encoder. + if FLAGS.uni_checkpoint_path: + print("Loading unidirectional model...") + uni_config = configuration.model_config() + encoder.load_model(uni_config, FLAGS.uni_vocab_file, + FLAGS.uni_embeddings_file, FLAGS.uni_checkpoint_path) + + # Maybe load bidirectional encoder. + if FLAGS.bi_checkpoint_path: + print("Loading bidirectional model...") + bi_config = configuration.model_config(bidirectional_encoder=True) + encoder.load_model(bi_config, FLAGS.bi_vocab_file, FLAGS.bi_embeddings_file, + FLAGS.bi_checkpoint_path) + + if FLAGS.eval_task in ["MR", "CR", "SUBJ", "MPQA"]: + eval_classification.eval_nested_kfold( + encoder, FLAGS.eval_task, FLAGS.data_dir, use_nb=False) + elif FLAGS.eval_task == "SICK": + eval_sick.evaluate(encoder, evaltest=True, loc=FLAGS.data_dir) + elif FLAGS.eval_task == "MSRP": + eval_msrp.evaluate( + encoder, evalcv=True, evaltest=True, use_feats=True, loc=FLAGS.data_dir) + elif FLAGS.eval_task == "TREC": + eval_trec.evaluate(encoder, evalcv=True, evaltest=True, loc=FLAGS.data_dir) + else: + raise ValueError("Unrecognized eval_task: %s" % FLAGS.eval_task) + + encoder.close() + + +if __name__ == "__main__": + tf.app.run() diff --git a/skip_thoughts/experiments.py b/skip_thoughts/experiments.py new file mode 100644 index 0000000..eb6bb13 --- /dev/null +++ b/skip_thoughts/experiments.py @@ -0,0 +1,51 @@ +# Copyright 2018 Babylon Partners. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Easy classes for decoder configurations.""" + + +def get_decoder_config(flags): + n_seq_decoders, n_skipgram_decoders = ( + int(flags.decoder[3]), int(flags.decoder[-1])) + + assert n_seq_decoders in [0, 1, 2, 3] + assert n_skipgram_decoders in [0, 1, 2, 3] + + decoder_config = DecoderConfig() + + if n_seq_decoders in [1, 3]: + decoder_config.sequence_decoder_cur = True + + if n_seq_decoders in [2, 3]: + decoder_config.sequence_decoder_pre = True + decoder_config.sequence_decoder_post = True + + if n_skipgram_decoders in [1, 3]: + decoder_config.skipgram_decoder_cur = True + + if n_skipgram_decoders in [2, 3]: + decoder_config.skipgram_decoder_pre = True + decoder_config.skipgram_decoder_post = True + + return decoder_config + + +class DecoderConfig: + def __init__(self): + self.sequence_decoder_pre = False + self.sequence_decoder_cur = False + self.sequence_decoder_post = False + self.skipgram_decoder_pre = False + self.skipgram_decoder_cur = False + self.skipgram_decoder_post = False diff --git a/skip_thoughts/ops/BUILD b/skip_thoughts/ops/BUILD new file mode 100644 index 0000000..4586e5a --- /dev/null +++ b/skip_thoughts/ops/BUILD @@ -0,0 +1,17 @@ +package(default_visibility = ["//skip_thoughts:internal"]) + +licenses(["notice"]) # Apache 2.0 + +exports_files(["LICENSE"]) + +py_library( + name = "input_ops", + srcs = ["input_ops.py"], + srcs_version = "PY2AND3", +) + +py_library( + name = "gru_cell", + srcs = ["gru_cell.py"], + srcs_version = "PY2AND3", +) diff --git a/skip_thoughts/ops/__init__.py b/skip_thoughts/ops/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/skip_thoughts/ops/gru_cell.py b/skip_thoughts/ops/gru_cell.py new file mode 100644 index 0000000..c4bee46 --- /dev/null +++ b/skip_thoughts/ops/gru_cell.py @@ -0,0 +1,134 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""GRU cell implementation for the skip-thought vectors model.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +import tensorflow as tf + +_layer_norm = tf.contrib.layers.layer_norm + + +class LayerNormGRUCell(tf.contrib.rnn.RNNCell): + """GRU cell with layer normalization. + + The layer normalization implementation is based on: + + https://arxiv.org/abs/1607.06450. + + "Layer Normalization" + Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton + """ + + def __init__(self, + num_units, + w_initializer, + u_initializer, + b_initializer, + activation=tf.nn.tanh): + """Initializes the cell. + + Args: + num_units: Number of cell units. + w_initializer: Initializer for the "W" (input) parameter matrices. + u_initializer: Initializer for the "U" (recurrent) parameter matrices. + b_initializer: Initializer for the "b" (bias) parameter vectors. + activation: Cell activation function. + """ + self._num_units = num_units + self._w_initializer = w_initializer + self._u_initializer = u_initializer + self._b_initializer = b_initializer + self._activation = activation + + @property + def state_size(self): + return self._num_units + + @property + def output_size(self): + return self._num_units + + def _w_h_initializer(self): + """Returns an initializer for the "W_h" parameter matrix. + + See equation (23) in the paper. The "W_h" parameter matrix is the + concatenation of two parameter submatrices. The matrix returned is + [U_z, U_r]. + + Returns: + A Tensor with shape [num_units, 2 * num_units] as described above. + """ + + def _initializer(shape, dtype=tf.float32, partition_info=None): + num_units = self._num_units + assert shape == [num_units, 2 * num_units] + u_z = self._u_initializer([num_units, num_units], dtype, partition_info) + u_r = self._u_initializer([num_units, num_units], dtype, partition_info) + return tf.concat([u_z, u_r], 1) + + return _initializer + + def _w_x_initializer(self, input_dim): + """Returns an initializer for the "W_x" parameter matrix. + + See equation (23) in the paper. The "W_x" parameter matrix is the + concatenation of two parameter submatrices. The matrix returned is + [W_z, W_r]. + + Args: + input_dim: The dimension of the cell inputs. + + Returns: + A Tensor with shape [input_dim, 2 * num_units] as described above. + """ + + def _initializer(shape, dtype=tf.float32, partition_info=None): + num_units = self._num_units + assert shape == [input_dim, 2 * num_units] + w_z = self._w_initializer([input_dim, num_units], dtype, partition_info) + w_r = self._w_initializer([input_dim, num_units], dtype, partition_info) + return tf.concat([w_z, w_r], 1) + + return _initializer + + def __call__(self, inputs, state, scope=None): + """GRU cell with layer normalization.""" + input_dim = inputs.get_shape().as_list()[1] + num_units = self._num_units + + with tf.variable_scope(scope or "gru_cell"): + with tf.variable_scope("gates"): + w_h = tf.get_variable( + "w_h", [num_units, 2 * num_units], + initializer=self._w_h_initializer()) + w_x = tf.get_variable( + "w_x", [input_dim, 2 * num_units], + initializer=self._w_x_initializer(input_dim)) + z_and_r = (_layer_norm(tf.matmul(state, w_h), scope="layer_norm/w_h") + + _layer_norm(tf.matmul(inputs, w_x), scope="layer_norm/w_x")) + z, r = tf.split(tf.sigmoid(z_and_r), 2, 1) + with tf.variable_scope("candidate"): + w = tf.get_variable( + "w", [input_dim, num_units], initializer=self._w_initializer) + u = tf.get_variable( + "u", [num_units, num_units], initializer=self._u_initializer) + h_hat = (r * _layer_norm(tf.matmul(state, u), scope="layer_norm/u") + + _layer_norm(tf.matmul(inputs, w), scope="layer_norm/w")) + new_h = (1 - z) * state + z * self._activation(h_hat) + return new_h, new_h diff --git a/skip_thoughts/ops/input_ops.py b/skip_thoughts/ops/input_ops.py new file mode 100644 index 0000000..6b84f42 --- /dev/null +++ b/skip_thoughts/ops/input_ops.py @@ -0,0 +1,119 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Input ops.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections + + +import tensorflow as tf +from tensorflow.python.ops import sparse_ops + +# A SentenceBatch is a pair of Tensors: +# ids: Batch of input sentences represented as sequences of word ids: an int64 +# Tensor with shape [batch_size, padded_length]. +# mask: Boolean mask distinguishing real words (1) from padded words (0): an +# int32 Tensor with shape [batch_size, padded_length]. +SentenceBatch = collections.namedtuple("SentenceBatch", ("ids", "mask")) + + +def parse_example_batch(serialized): + """Parses a batch of tf.Example protos. + + Args: + serialized: A 1-D string Tensor; a batch of serialized tf.Example protos. + Returns: + encode: A SentenceBatch of encode sentences. + decode_pre: A SentenceBatch of "previous" sentences to decode. + decode_post: A SentenceBatch of "post" sentences to decode. + """ + features = tf.parse_example( + serialized, + features={ + "encode": tf.VarLenFeature(dtype=tf.int64), + "decode_pre": tf.VarLenFeature(dtype=tf.int64), + "decode_post": tf.VarLenFeature(dtype=tf.int64), + }) + + def _sparse_to_batch(sparse): + ids = tf.sparse_tensor_to_dense(sparse) # Padding with zeroes. + mask = tf.sparse_to_dense(sparse.indices, sparse.dense_shape, + tf.ones_like(sparse.values, dtype=tf.int32)) + return SentenceBatch(ids=ids, mask=mask) + + output_names = ("encode", "decode_pre", "decode_post") + return tuple(_sparse_to_batch(features[x]) for x in output_names) + + +def prefetch_input_data(reader, + file_pattern, + shuffle, + capacity, + num_reader_threads=1): + """Prefetches string values from disk into an input queue. + + Args: + reader: Instance of tf.ReaderBase. + file_pattern: Comma-separated list of file patterns (e.g. + "/tmp/train_data-?????-of-00100", where '?' acts as a wildcard that + matches any character). + shuffle: Boolean; whether to randomly shuffle the input data. + capacity: Queue capacity (number of records). + num_reader_threads: Number of reader threads feeding into the queue. + + Returns: + A Queue containing prefetched string values. + """ + data_files = [] + for pattern in file_pattern.split(","): + data_files.extend(tf.gfile.Glob(pattern)) + if not data_files: + tf.logging.fatal("Found no input files matching %s", file_pattern) + else: + tf.logging.info("Prefetching values from %d files matching %s", + len(data_files), file_pattern) + + filename_queue = tf.train.string_input_producer( + data_files, shuffle=shuffle, capacity=16, name="filename_queue") + + if shuffle: + min_after_dequeue = int(0.6 * capacity) + values_queue = tf.RandomShuffleQueue( + capacity=capacity, + min_after_dequeue=min_after_dequeue, + dtypes=[tf.string], + shapes=[[]], + name="random_input_queue") + else: + values_queue = tf.FIFOQueue( + capacity=capacity, + dtypes=[tf.string], + shapes=[[]], + name="fifo_input_queue") + + enqueue_ops = [] + for _ in range(num_reader_threads): + _, value = reader.read(filename_queue) + enqueue_ops.append(values_queue.enqueue([value])) + tf.train.queue_runner.add_queue_runner( + tf.train.queue_runner.QueueRunner(values_queue, enqueue_ops)) + tf.summary.scalar("queue/%s/fraction_of_%d_full" % (values_queue.name, + capacity), + tf.cast(values_queue.size(), tf.float32) * (1.0 / capacity)) + + return values_queue diff --git a/skip_thoughts/pretrained_embeddings.py b/skip_thoughts/pretrained_embeddings.py new file mode 100644 index 0000000..6861e32 --- /dev/null +++ b/skip_thoughts/pretrained_embeddings.py @@ -0,0 +1,97 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Changes by Babylon Partners +# - Modified skip_thoughts/vocabulary_expansion.py to +# prepare pretrained embeddings +# ============================================================================== + + +import os +import collections +import tensorflow as tf +import numpy as np +import gensim + + +FLAGS = tf.flags.FLAGS + +tf.flags.DEFINE_string("vocab_file", None, + "Existing vocab file." + "The file format is a list of newline-separated words, " + "where the word id is the corresponding 0-based index " + "in the file. The 0th word must correspond to the " + "token and the 1st word to the token.") +tf.flags.DEFINE_string("word2vec_model", None, + "File containing a word2vec model in binary format.") +tf.flags.DEFINE_string("output_dir", None, "Output directory.") + +tf.logging.set_verbosity(tf.logging.INFO) + + +def _get_vocabulary(): + """Loads the model vocabulary. + + + Returns: + vocab: A dictionary of word to id. + """ + if not FLAGS.vocab_file: + raise RuntimeError("No vocab file specified.") + + tf.logging.info("Loading existing vocab file.") + vocab = collections.OrderedDict() + with tf.gfile.GFile(FLAGS.vocab_file, mode="r") as f: + for i, line in enumerate(f): + word = line.strip().decode("utf-8") + assert word not in vocab, "Attempting to add word twice: %s" % word + vocab[word] = i + tf.logging.info("Read vocab of size %d from %s", + len(vocab), FLAGS.vocab_file) + return vocab + + +def main(unused_argv): + vocab = _get_vocabulary() + tf.logging.info("Loading word2vec model.") + w2v_model = gensim.models.KeyedVectors.load_word2vec_format( + FLAGS.word2vec_model, binary=True) + tf.logging.info("Loaded word2vec model.") + + vocab_size = len(vocab) + init_embeddings = np.zeros(shape=(vocab_size, w2v_model.vector_size), + dtype=np.float32) + eos_vector = np.zeros(shape=(1, w2v_model.vector_size), + dtype=np.float32) + eos_vector[0][0] = -1 + unk_vector = np.zeros(shape=(1, w2v_model.vector_size), + dtype=np.float32) + unk_vector[0][-1] = -1 + + tf.logging.info("Building embedding matrix.") + for word, idx in vocab.items(): + if word in w2v_model: + init_embeddings[idx] = w2v_model[word] + else: + init_embeddings[idx] = unk_vector + init_embeddings[0] = eos_vector + init_embeddings[1] = unk_vector + embeddings_file = os.path.join(FLAGS.output_dir, "init_embeddings.npy") + if not os.path.exists(FLAGS.output_dir): + os.makedirs(FLAGS.output_dir) + np.save(embeddings_file, init_embeddings) + + +if __name__ == "__main__": + tf.app.run() diff --git a/skip_thoughts/skip_thoughts_encoder.py b/skip_thoughts/skip_thoughts_encoder.py new file mode 100644 index 0000000..89e58ba --- /dev/null +++ b/skip_thoughts/skip_thoughts_encoder.py @@ -0,0 +1,262 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Changes by Babylon Partners +# - Added new encode-decode mode +# ============================================================================== +"""Class for encoding text using a trained SkipThoughtsModel. + +Example usage: + g = tf.Graph() + with g.as_default(): + encoder = SkipThoughtsEncoder(embeddings) + restore_fn = encoder.build_graph_from_config(model_config, checkpoint_path) + + with tf.Session(graph=g) as sess: + restore_fn(sess) + skip_thought_vectors = encoder.encode(sess, data) +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os.path + + +import nltk +import nltk.tokenize +import numpy as np +import tensorflow as tf + +from skip_thoughts import skip_thoughts_model +from skip_thoughts.data import special_words + + +def _pad(seq, target_len): + """Pads a sequence of word embeddings up to the target length. + + Args: + seq: Sequence of word embeddings. + target_len: Desired padded sequence length. + + Returns: + embeddings: Input sequence padded with zero embeddings up to the target + length. + mask: A 0/1 vector with zeros corresponding to padded embeddings. + + Raises: + ValueError: If len(seq) is not in the interval (0, target_len]. + """ + seq_len = len(seq) + if seq_len <= 0 or seq_len > target_len: + raise ValueError("Expected 0 < len(seq) <= %d, got %d" % (target_len, + seq_len)) + + emb_dim = seq[0].shape[0] + padded_seq = np.zeros(shape=(target_len, emb_dim), dtype=seq[0].dtype) + mask = np.zeros(shape=(target_len,), dtype=np.int8) + for i in range(seq_len): + padded_seq[i] = seq[i] + mask[i] = 1 + return padded_seq, mask + + +def _batch_and_pad(sequences): + """Batches and pads sequences of word embeddings into a 2D array. + + Args: + sequences: A list of batch_size sequences of word embeddings. + + Returns: + embeddings: A numpy array with shape [batch_size, padded_length, emb_dim]. + mask: A numpy 0/1 array with shape [batch_size, padded_length] with zeros + corresponding to padded elements. + """ + batch_embeddings = [] + batch_mask = [] + batch_len = max([len(seq) for seq in sequences]) + for seq in sequences: + embeddings, mask = _pad(seq, batch_len) + batch_embeddings.append(embeddings) + batch_mask.append(mask) + return np.array(batch_embeddings), np.array(batch_mask) + + +class SkipThoughtsEncoder(object): + """Skip-thoughts sentence encoder.""" + + def __init__(self, embeddings): + """Initializes the encoder. + + Args: + embeddings: Dictionary of word to embedding vector (1D numpy array). + """ + self._sentence_detector = nltk.data.load("tokenizers/punkt/english.pickle") + self._embeddings = embeddings + + def _create_restore_fn(self, checkpoint_path, saver): + """Creates a function that restores a model from checkpoint. + + Args: + checkpoint_path: Checkpoint file or a directory containing a checkpoint + file. + saver: Saver for restoring variables from the checkpoint file. + + Returns: + restore_fn: A function such that restore_fn(sess) loads model variables + from the checkpoint file. + + Raises: + ValueError: If checkpoint_path does not refer to a checkpoint file or a + directory containing a checkpoint file. + """ + if tf.gfile.IsDirectory(checkpoint_path): + latest_checkpoint = tf.train.latest_checkpoint(checkpoint_path) + if not latest_checkpoint: + raise ValueError("No checkpoint file found in: %s" % checkpoint_path) + checkpoint_path = latest_checkpoint + + def _restore_fn(sess): + tf.logging.info("Loading model from checkpoint: %s", checkpoint_path) + saver.restore(sess, checkpoint_path) + tf.logging.info("Successfully loaded checkpoint: %s", + os.path.basename(checkpoint_path)) + + return _restore_fn + + def build_graph_from_config(self, model_config, checkpoint_path, + mode="encode"): + """Builds the inference graph from a configuration object. + + Args: + model_config: Object containing configuration for building the model. + checkpoint_path: Checkpoint file or a directory containing a checkpoint + file. + + Returns: + restore_fn: A function such that restore_fn(sess) loads model variables + from the checkpoint file. + """ + tf.logging.info("Building model.") + model = skip_thoughts_model.SkipThoughtsModel(model_config, mode=mode) + model.build() + saver = tf.train.Saver() + + return self._create_restore_fn(checkpoint_path, saver) + + def build_graph_from_proto(self, graph_def_file, saver_def_file, + checkpoint_path): + """Builds the inference graph from serialized GraphDef and SaverDef protos. + + Args: + graph_def_file: File containing a serialized GraphDef proto. + saver_def_file: File containing a serialized SaverDef proto. + checkpoint_path: Checkpoint file or a directory containing a checkpoint + file. + + Returns: + restore_fn: A function such that restore_fn(sess) loads model variables + from the checkpoint file. + """ + # Load the Graph. + tf.logging.info("Loading GraphDef from file: %s", graph_def_file) + graph_def = tf.GraphDef() + with tf.gfile.FastGFile(graph_def_file, "rb") as f: + graph_def.ParseFromString(f.read()) + tf.import_graph_def(graph_def, name="") + + # Load the Saver. + tf.logging.info("Loading SaverDef from file: %s", saver_def_file) + saver_def = tf.train.SaverDef() + with tf.gfile.FastGFile(saver_def_file, "rb") as f: + saver_def.ParseFromString(f.read()) + saver = tf.train.Saver(saver_def=saver_def) + + return self._create_restore_fn(checkpoint_path, saver) + + def _tokenize(self, item): + """Tokenizes an input string into a list of words.""" + tokenized = [] + for s in self._sentence_detector.tokenize(item): + tokenized.extend(nltk.tokenize.word_tokenize(s)) + + return tokenized + + def _word_to_embedding(self, w): + """Returns the embedding of a word.""" + return self._embeddings.get(w, self._embeddings[special_words.UNK]) + + def _preprocess(self, data, use_eos): + """Preprocesses text for the encoder. + + Args: + data: A list of input strings. + use_eos: Whether to append the end-of-sentence word to each sentence. + + Returns: + embeddings: A list of word embedding sequences corresponding to the input + strings. + """ + preprocessed_data = [] + for item in data: + tokenized = self._tokenize(item) + if use_eos: + tokenized.append(special_words.EOS) + preprocessed_data.append([self._word_to_embedding(w) for w in tokenized]) + return preprocessed_data + + def encode(self, + sess, + data, + use_norm=True, + verbose=True, + batch_size=128, + use_eos=False): + """Encodes a sequence of sentences as skip-thought vectors. + + Args: + sess: TensorFlow Session. + data: A list of input strings. + use_norm: Whether to normalize skip-thought vectors to unit L2 norm. + verbose: Whether to log every batch. + batch_size: Batch size for the encoder. + use_eos: Whether to append the end-of-sentence word to each input + sentence. + + Returns: + thought_vectors: A list of numpy arrays corresponding to the skip-thought + encodings of sentences in 'data'. + """ + data = self._preprocess(data, use_eos) + thought_vectors = [] + + batch_indices = np.arange(0, len(data), batch_size) + for batch, start_index in enumerate(batch_indices): + if verbose: + tf.logging.info("Batch %d / %d.", batch, len(batch_indices)) + + embeddings, mask = _batch_and_pad( + data[start_index:start_index + batch_size]) + feed_dict = { + "encode_emb:0": embeddings, + "encode_mask:0": mask, + } + thought_vectors.extend( + sess.run("encoder/thought_vectors:0", feed_dict=feed_dict)) + + if use_norm: + thought_vectors = [v / np.linalg.norm(v) for v in thought_vectors] + + return thought_vectors diff --git a/skip_thoughts/skip_thoughts_model.py b/skip_thoughts/skip_thoughts_model.py new file mode 100644 index 0000000..a635f1f --- /dev/null +++ b/skip_thoughts/skip_thoughts_model.py @@ -0,0 +1,559 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Changes by Babylon Partners +# - Added code to support sequence and skipgram +# decoders for previous, current, and next sentences +# - Added _build_skipgram_decoder function +# - Added encode-decode mode +# - Added code to support decoder unrolling +# - Added summaries +# ============================================================================== +"""Skip-Thoughts model for learning sentence vectors. + +The model is based on the paper: + + "Skip-Thought Vectors" + Ryan Kiros, Yukun Zhu, Ruslan Salakhutdinov, Richard S. Zemel, + Antonio Torralba, Raquel Urtasun, Sanja Fidler. + https://papers.nips.cc/paper/5950-skip-thought-vectors.pdf + +Layer normalization is applied based on the paper: + + "Layer Normalization" + Jimmy Lei Ba, Jamie Ryan Kiros, Geoffrey E. Hinton + https://arxiv.org/abs/1607.06450 +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + + +import tensorflow as tf +import numpy as np +from skip_thoughts.ops import gru_cell +from skip_thoughts.ops import input_ops + +import skip_thoughts.summaries as summaries + + +def random_orthonormal_initializer(shape, dtype=tf.float32, + partition_info=None): + # pylint: disable=unused-argument + """Variable initializer that produces a random orthonormal matrix.""" + if len(shape) != 2 or shape[0] != shape[1]: + raise ValueError("Expecting square shape, got %s" % shape) + _, u, _ = tf.svd(tf.random_normal(shape, dtype=dtype), full_matrices=True) + return u + + +class SkipThoughtsModel(object): + """Skip-thoughts model.""" + + def __init__(self, config, mode="train", input_reader=None): + """Basic setup. The actual TensorFlow graph is constructed in build(). + + Args: + config: Object containing configuration parameters. + mode: "train", "eval" or "encode". + input_reader: Subclass of tf.ReaderBase for reading the input + serialized tf.Example protocol buffers. Defaults to + TFRecordReader. + + Raises: + ValueError: If mode is invalid. + """ + if mode not in ["train", "eval", "encode", "encode-decode"]: + raise ValueError("Unrecognized mode: %s" % mode) + + self.config = config + self.mode = mode + self.reader = input_reader if input_reader else tf.TFRecordReader() + + # Initializer used for non-recurrent weights. + self.uniform_initializer = tf.random_uniform_initializer( + minval=-self.config.uniform_init_scale, + maxval=self.config.uniform_init_scale) + + # Input sentences represented as sequences of word ids. + # "encode" is the source sentence, + # "decode_pre" is the previous sentence and + # "decode_post" is the next sentence. + # Each is an int64 Tensor with shape [batch_size, padded_length]. + self.encode_ids = None + self.decode_pre_ids = None + self.decode_post_ids = None + + # Boolean masks distinguishing real words (1) from padded words (0). + # Each is an int32 Tensor with shape [batch_size, padded_length]. + self.encode_mask = None + self.decode_pre_mask = None + self.decode_post_mask = None + + # Input sentences represented as sequences of word embeddings. + # Each is a float32 Tensor with shape + # [batch_size, padded_length, emb_dim]. + self.encode_emb = None + self.decode_pre_emb = None + self.decode_post_emb = None + + # The output from the sentence encoder. + # A float32 Tensor with shape [batch_size, num_gru_units]. + self.thought_vectors = None + + # The cross entropy losses and corresponding weights of the decoders. + # Used for evaluation. + self.target_cross_entropy_losses = [] + self.target_cross_entropy_loss_weights = [] + + # The total loss to optimize. + self.total_loss = None + + tvars = tf.trainable_variables() + with tf.name_scope('trainable_vars'): + # Summarise all variables + for var in tvars: + summaries.variable_summaries(var, summary_prefix=var.name) + + def build_inputs(self): + """Builds the ops for reading input data. + + Outputs: + self.encode_ids + self.decode_pre_ids + self.decode_post_ids + self.encode_mask + self.decode_pre_mask + self.decode_post_mask + """ + if self.mode == "encode": + # Word embeddings are fed from an external vocabulary which has + # possibly been expanded (see vocabulary_expansion.py). + encode_ids = None + decode_pre_ids = None + decode_post_ids = None + + encode_mask = tf.placeholder( + tf.int8, (None, None), name="encode_mask") + decode_pre_mask = None + decode_post_mask = None + elif self.mode == "encode-decode": + # Word embeddings are fed from an external vocabulary which has + # possibly been expanded (see vocabulary_expansion.py). + encode_ids = None + decode_pre_ids = None + decode_post_ids = None + + encode_mask = tf.placeholder( + tf.int8, (None, None), name="encode_mask") + decode_pre_mask = tf.placeholder( + tf.int8, (None, None), name="decode_pre_mask") + decode_post_mask = tf.placeholder( + tf.int8, (None, None), name="decode_post_mask") + else: + # Prefetch serialized tf.Example protos. + input_queue = input_ops.prefetch_input_data( + self.reader, + self.config.input_file_pattern, + shuffle=self.config.shuffle_input_data, + capacity=self.config.input_queue_capacity, + num_reader_threads=self.config.num_input_reader_threads) + + # Deserialize a batch. + serialized = input_queue.dequeue_many(self.config.batch_size) + encode, decode_pre, decode_post = input_ops.parse_example_batch( + serialized) + + encode_ids = encode.ids + decode_pre_ids = decode_pre.ids + decode_post_ids = decode_post.ids + + encode_mask = encode.mask + decode_pre_mask = decode_pre.mask + decode_post_mask = decode_post.mask + + self.encode_ids = encode_ids + self.decode_pre_ids = decode_pre_ids + self.decode_post_ids = decode_post_ids + + self.encode_mask = encode_mask + self.decode_pre_mask = decode_pre_mask + self.decode_post_mask = decode_post_mask + + def build_word_embeddings(self): + """Builds the word embeddings. + + Inputs: + self.encode_ids + self.decode_pre_ids + self.decode_post_ids + + Outputs: + self.encode_emb + self.decode_pre_emb + self.decode_post_emb + """ + if self.mode == "encode": + # Word embeddings are fed from an external vocabulary which has + # possibly been expanded (see vocabulary_expansion.py). + encode_emb = tf.placeholder(tf.float32, ( + None, None, self.config.word_embedding_dim), "encode_emb") + # No sequences to decode. + decode_pre_emb = None + decode_post_emb = None + elif self.mode == "encode-decode": + # Word embeddings are fed from an external vocabulary which has + # possibly been expanded (see vocabulary_expansion.py). + encode_emb = tf.placeholder(tf.float32, ( + None, None, self.config.word_embedding_dim), "encode_emb") + decode_pre_emb = tf.placeholder(tf.float32, ( + None, None, self.config.word_embedding_dim), "decode_pre_emb") + decode_post_emb = tf.placeholder(tf.float32, ( + None, None, self.config.word_embedding_dim), "decode_post_emb") + + word_emb = tf.get_variable( + name="word_embedding", + shape=[self.config.vocab_size, self.config.word_embedding_dim], + initializer=self.uniform_initializer) + else: + if self.config.pretrained_word_emb_file: + word_emb_values = np.load(self.config.pretrained_word_emb_file) + assert self.config.word_embedding_dim == word_emb_values.shape[1] + + word_emb = tf.get_variable( + name="word_embedding", + initializer=tf.constant(word_emb_values, dtype=tf.float32), + trainable=self.config.word_emb_trainable) + else: + word_emb = tf.get_variable( + name="word_embedding", + shape=[self.config.vocab_size, self.config.word_embedding_dim], + initializer=self.uniform_initializer) + + encode_emb = tf.nn.embedding_lookup(word_emb, self.encode_ids) + decode_pre_emb = tf.nn.embedding_lookup(word_emb, self.decode_pre_ids) + decode_post_emb = tf.nn.embedding_lookup(word_emb, self.decode_post_ids) + + self.encode_emb = encode_emb + self.decode_pre_emb = decode_pre_emb + self.decode_post_emb = decode_post_emb + + def _initialize_gru_cell(self, num_units): + """Initializes a GRU cell. + + The Variables of the GRU cell are initialized in a way that exactly matches + the skip-thoughts paper: recurrent weights are initialized from random + orthonormal matrices and non-recurrent weights are initialized from random + uniform matrices. + + Args: + num_units: Number of output units. + + Returns: + cell: An instance of RNNCell with variable initializers that match the + skip-thoughts paper. + """ + return gru_cell.LayerNormGRUCell( + num_units, + w_initializer=self.uniform_initializer, + u_initializer=random_orthonormal_initializer, + b_initializer=tf.constant_initializer(0.0)) + + def build_encoder(self): + """Builds the sentence encoder. + + Inputs: + self.encode_emb + self.encode_mask + + Outputs: + self.thought_vectors + + Raises: + ValueError: if config.bidirectional_encoder is True and config.encoder_dim + is odd. + """ + with tf.variable_scope("encoder") as scope: + if self.config.skipgram_encoder: + w_dim = self.config.word_embedding_dim + e_dim = self.config.encoder_dim + + # For FastSent sentence emb dim is the same word emb dim + assert w_dim == e_dim + + encode_emb = tf.reshape(self.encode_emb, [-1, w_dim]) + weights = tf.to_float(tf.reshape(self.encode_mask, [-1, 1])) + encode_emb = encode_emb * weights + seq_len = tf.shape(self.encode_mask)[-1] + encode_emb = tf.reshape(encode_emb, tf.stack([-1, seq_len, w_dim])) + + self.thought_vectors = tf.reduce_sum(encode_emb, + axis=1, + name="thought_vectors") + return + + length = tf.to_int32(tf.reduce_sum(self.encode_mask, 1), name="length") + + if self.config.bidirectional_encoder: + if self.config.encoder_dim % 2: + raise ValueError( + "encoder_dim must be even when using a bidirectional encoder.") + num_units = self.config.encoder_dim // 2 + cell_fw = self._initialize_gru_cell(num_units) # Forward encoder + cell_bw = self._initialize_gru_cell(num_units) # Backward encoder + _, states = tf.nn.bidirectional_dynamic_rnn( + cell_fw=cell_fw, + cell_bw=cell_bw, + inputs=self.encode_emb, + sequence_length=length, + dtype=tf.float32, + scope=scope) + thought_vectors = tf.concat(states, 1, name="thought_vectors") + else: + cell = self._initialize_gru_cell(self.config.encoder_dim) + _, state = tf.nn.dynamic_rnn( + cell=cell, + inputs=self.encode_emb, + sequence_length=length, + dtype=tf.float32, + scope=scope) + # Use an identity operation to name the Tensor in the Graph. + thought_vectors = tf.identity(state, name="thought_vectors") + + self.thought_vectors = thought_vectors + + def _build_sequence_decoder(self, name, embeddings, targets, mask, + initial_state, reuse_logits): + """Builds a sentence decoder. + + Args: + name: Decoder name. + embeddings: Batch of sentences to decode; a float32 Tensor with shape + [batch_size, padded_length, emb_dim]. + targets: Batch of target word ids; an int64 Tensor with shape + [batch_size, padded_length]. + mask: A 0/1 Tensor with shape [batch_size, padded_length]. + initial_state: Initial state of the GRU. A float32 Tensor with shape + [batch_size, num_gru_cells]. + reuse_logits: Whether to reuse the logits weights. + """ + # Decoder RNN. + cell = self._initialize_gru_cell(self.config.encoder_dim) + with tf.variable_scope(name) as scope: + # Add a padding word at the start of each sentence (to correspond to the + # prediction of the first word) and remove the last word. + decoder_input = tf.pad( + embeddings[:, :-1, :], [[0, 0], [1, 0], [0, 0]], name="input") + length = tf.reduce_sum(mask, 1, name="length") + decoder_output, decoder_state = tf.nn.dynamic_rnn( + cell=cell, + inputs=decoder_input, + sequence_length=length, + initial_state=initial_state, + scope=scope) + + decoder_output = tf.identity(decoder_output, name='decoder_output') + decoder_state = tf.identity(decoder_state, name='decoder_state') + + # Stack batch vertically. + decoder_output = tf.reshape(decoder_output, [-1, self.config.encoder_dim]) + + # Logits. + with tf.variable_scope("logits", reuse=reuse_logits) as scope: + logits = tf.contrib.layers.fully_connected( + inputs=decoder_output, + num_outputs=self.config.vocab_size, + activation_fn=None, + weights_initializer=self.uniform_initializer, + scope=scope) + + logits = tf.identity(logits, name='logits/' + name) + + # If we just want the encode-decode, stop here + if self.mode == "encode-decode": + return None + + targets = tf.reshape(targets, [-1]) + weights = tf.to_float(tf.reshape(mask, [-1])) + + losses = tf.nn.sparse_softmax_cross_entropy_with_logits( + labels=targets, logits=logits) + batch_loss = tf.reduce_sum(losses * weights) + + if self.config.normalise_decoder_losses: + batch_loss = batch_loss / self.config.num_sequence_decoders + + batch_loss = batch_loss * self.config.sequence_prefactor + + tf.losses.add_loss(batch_loss) + + tf.summary.scalar("losses/" + name, batch_loss) + + self.target_cross_entropy_losses.append(losses) + self.target_cross_entropy_loss_weights.append(weights) + + def _build_skipgram_decoder(self, name, targets, mask, reuse_logits): + + """Builds a skipgram decoder. + + Args: + name: Decoder name. + targets: Batch of target word ids; an int64 Tensor with shape + [batch_size, padded_length]. + mask: A 0/1 Tensor with shape [batch_size, padded_length]. + reuse_logits: Whether to reuse the logits weights. + """ + + with tf.variable_scope("skipgram_logits", reuse=reuse_logits) as scope: + skipgram_logits = tf.contrib.layers.fully_connected( + inputs=self.thought_vectors, + num_outputs=self.config.vocab_size, + activation_fn=None, + weights_initializer=self.uniform_initializer, + scope=scope) + + if self.mode == "encode-decode": + return None + + multiples = tf.stack([1, tf.shape(targets)[-1], 1]) + skipgram_logits = tf.expand_dims(skipgram_logits, 1) + skipgram_logits = tf.tile(skipgram_logits, multiples) + skipgram_logits = tf.reshape(skipgram_logits, [-1, self.config.vocab_size]) + + targets = tf.reshape(targets, [-1]) + weights = tf.to_float(tf.reshape(mask, [-1])) + + losses = tf.nn.sparse_softmax_cross_entropy_with_logits( + labels=targets, logits=skipgram_logits) + + batch_loss = tf.reduce_sum(losses * weights) + + if self.config.normalise_decoder_losses: + batch_loss = batch_loss / self.config.num_skipgram_decoders + + batch_loss = batch_loss * self.config.skipgram_prefactor + + tf.losses.add_loss(batch_loss) + + tf.summary.scalar("losses/" + name, batch_loss) + + self.target_cross_entropy_losses.append(losses) + self.target_cross_entropy_loss_weights.append(weights) + + def build_sequence_decoders(self): + """Builds the sentence decoders. + + Inputs: + self.decode_pre_emb + self.decode_post_emb + self.decode_pre_ids + self.decode_post_ids + self.decode_pre_mask + self.decode_post_mask + self.thought_vectors + + Outputs: + self.target_cross_entropy_losses + self.target_cross_entropy_loss_weights + """ + reuse_logits = False + if self.config.sequence_decoder_pre: + # Pre-sentence decoder. + self._build_sequence_decoder("decoder_pre", self.decode_pre_emb, + self.decode_pre_ids, self.decode_pre_mask, + self.thought_vectors, reuse_logits) + reuse_logits = True + + if self.config.sequence_decoder_post: + # Post-sentence decoder. Logits weights are reused. + self._build_sequence_decoder("decoder_post", self.decode_post_emb, + self.decode_post_ids, self.decode_post_mask, + self.thought_vectors, reuse_logits) + reuse_logits = True + + if self.config.sequence_decoder_cur: + # Cur-sentence decoder. Logits weights are reused. + self._build_sequence_decoder("decoder_cur", self.encode_emb, + self.encode_ids, self.encode_mask, + self.thought_vectors, reuse_logits) + + def build_skipgram_decoders(self): + """Builds the sentence decoders. + + Inputs: + self.decode_pre_ids + self.decode_post_ids + self.decode_pre_mask + self.decode_post_mask + self.thought_vectors + + Outputs: + self.target_cross_entropy_losses + self.target_cross_entropy_loss_weights + """ + reuse_logits = False + if self.config.skipgram_decoder_pre: + # Pre-sentence decoder. + self._build_skipgram_decoder("skipgram_pre", + self.decode_pre_ids, self.decode_pre_mask, + reuse_logits) + reuse_logits = True + + if self.config.skipgram_decoder_post: + # Post-sentence decoder. Logits weights are reused. + self._build_skipgram_decoder("skipgram_post", + self.decode_post_ids, self.decode_post_mask, + reuse_logits) + reuse_logits = True + + if self.config.skipgram_decoder_cur: + # Cur-sentence decoder. Logits weights are reused. + self._build_skipgram_decoder("skipgram_cur", + self.encode_ids, self.encode_mask, + reuse_logits) + + def build_decoders(self): + if self.mode != "encode": + self.build_sequence_decoders() + self.build_skipgram_decoders() + + def build_loss(self): + """Builds the loss Tensor. + + Outputs: + self.total_loss + """ + if self.mode not in ["encode", 'encode-decode']: + total_loss = tf.losses.get_total_loss() + tf.summary.scalar("losses/total", total_loss) + + self.total_loss = total_loss + + def build_global_step(self): + """Builds the global step Tensor. + + Outputs: + self.global_step + """ + self.global_step = tf.contrib.framework.create_global_step() + + def build(self): + """Creates all ops for training, evaluation or encoding.""" + self.build_inputs() + self.build_word_embeddings() + self.build_encoder() + self.build_decoders() + self.build_loss() + self.build_global_step() diff --git a/skip_thoughts/summaries.py b/skip_thoughts/summaries.py new file mode 100644 index 0000000..35be983 --- /dev/null +++ b/skip_thoughts/summaries.py @@ -0,0 +1,34 @@ +# Copyright 2018 Babylon Partners. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== + +import tensorflow as tf + + +def variable_summaries(var, summary_prefix): + """Attach a lot of summaries to a Tensor + (for TensorBoard visualization).""" + mean = tf.reduce_mean(var) + tf.summary.scalar('{sp} mean'.format( + sp=summary_prefix), mean) + with tf.name_scope('stddev'): + stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean))) + tf.summary.scalar('{sp} stddev'.format( + sp=summary_prefix), stddev) + tf.summary.scalar('{sp} max'.format( + sp=summary_prefix), tf.reduce_max(var)) + tf.summary.scalar('{sp} min'.format( + sp=summary_prefix), tf.reduce_min(var)) + tf.summary.histogram('{sp} histogram'.format( + sp=summary_prefix), var) diff --git a/skip_thoughts/track_perplexity.py b/skip_thoughts/track_perplexity.py new file mode 100644 index 0000000..05d0e33 --- /dev/null +++ b/skip_thoughts/track_perplexity.py @@ -0,0 +1,199 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Tracks training progress via per-word perplexity. + +This script should be run concurrently with training so that summaries show up +in TensorBoard. +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import math +import os.path +import time + + +import numpy as np +import tensorflow as tf + +from skip_thoughts import configuration +from skip_thoughts import skip_thoughts_model + +FLAGS = tf.flags.FLAGS + +tf.flags.DEFINE_string("input_file_pattern", None, + "File pattern of sharded TFRecord input files.") +tf.flags.DEFINE_string("checkpoint_dir", None, + "Directory containing model checkpoints.") +tf.flags.DEFINE_string("eval_dir", None, "Directory to write event logs to.") + +tf.flags.DEFINE_integer("eval_interval_secs", 600, + "Interval between evaluation runs.") +tf.flags.DEFINE_integer("num_eval_examples", 50000, + "Number of examples for evaluation.") + +tf.flags.DEFINE_integer("min_global_step", 100, + "Minimum global step to run evaluation.") + +tf.logging.set_verbosity(tf.logging.INFO) + + +def evaluate_model(sess, losses, weights, num_batches, global_step, + summary_writer, summary_op): + """Computes perplexity-per-word over the evaluation dataset. + + Summaries and perplexity-per-word are written out to the eval directory. + + Args: + sess: Session object. + losses: A Tensor of any shape; the target cross entropy losses for the + current batch. + weights: A Tensor of weights corresponding to losses. + num_batches: Integer; the number of evaluation batches. + global_step: Integer; global step of the model checkpoint. + summary_writer: Instance of SummaryWriter. + summary_op: Op for generating model summaries. + """ + # Log model summaries on a single batch. + summary_str = sess.run(summary_op) + summary_writer.add_summary(summary_str, global_step) + + start_time = time.time() + sum_losses = 0.0 + sum_weights = 0.0 + for i in xrange(num_batches): + batch_losses, batch_weights = sess.run([losses, weights]) + sum_losses += np.sum(batch_losses * batch_weights) + sum_weights += np.sum(batch_weights) + if not i % 100: + tf.logging.info("Computed losses for %d of %d batches.", i + 1, + num_batches) + eval_time = time.time() - start_time + + perplexity = math.exp(sum_losses / sum_weights) + tf.logging.info("Perplexity = %f (%.2f sec)", perplexity, eval_time) + + # Log perplexity to the SummaryWriter. + summary = tf.Summary() + value = summary.value.add() + value.simple_value = perplexity + value.tag = "perplexity" + summary_writer.add_summary(summary, global_step) + + # Write the Events file to the eval directory. + summary_writer.flush() + tf.logging.info("Finished processing evaluation at global step %d.", + global_step) + + +def run_once(model, losses, weights, saver, summary_writer, summary_op): + """Evaluates the latest model checkpoint. + + Args: + model: Instance of SkipThoughtsModel; the model to evaluate. + losses: Tensor; the target cross entropy losses for the current batch. + weights: A Tensor of weights corresponding to losses. + saver: Instance of tf.train.Saver for restoring model Variables. + summary_writer: Instance of FileWriter. + summary_op: Op for generating model summaries. + """ + model_path = tf.train.latest_checkpoint(FLAGS.checkpoint_dir) + if not model_path: + tf.logging.info("Skipping evaluation. No checkpoint found in: %s", + FLAGS.checkpoint_dir) + return + + with tf.Session() as sess: + # Load model from checkpoint. + tf.logging.info("Loading model from checkpoint: %s", model_path) + saver.restore(sess, model_path) + global_step = tf.train.global_step(sess, model.global_step.name) + tf.logging.info("Successfully loaded %s at global step = %d.", + os.path.basename(model_path), global_step) + if global_step < FLAGS.min_global_step: + tf.logging.info("Skipping evaluation. Global step = %d < %d", global_step, + FLAGS.min_global_step) + return + + # Start the queue runners. + coord = tf.train.Coordinator() + threads = tf.train.start_queue_runners(coord=coord) + + num_eval_batches = int( + math.ceil(FLAGS.num_eval_examples / model.config.batch_size)) + + # Run evaluation on the latest checkpoint. + try: + evaluate_model(sess, losses, weights, num_eval_batches, global_step, + summary_writer, summary_op) + except tf.InvalidArgumentError: + tf.logging.error( + "Evaluation raised InvalidArgumentError (e.g. due to Nans).") + finally: + coord.request_stop() + coord.join(threads, stop_grace_period_secs=10) + + +def main(unused_argv): + if not FLAGS.input_file_pattern: + raise ValueError("--input_file_pattern is required.") + if not FLAGS.checkpoint_dir: + raise ValueError("--checkpoint_dir is required.") + if not FLAGS.eval_dir: + raise ValueError("--eval_dir is required.") + + # Create the evaluation directory if it doesn't exist. + eval_dir = FLAGS.eval_dir + if not tf.gfile.IsDirectory(eval_dir): + tf.logging.info("Creating eval directory: %s", eval_dir) + tf.gfile.MakeDirs(eval_dir) + + g = tf.Graph() + with g.as_default(): + # Build the model for evaluation. + model_config = configuration.model_config( + input_file_pattern=FLAGS.input_file_pattern, + input_queue_capacity=FLAGS.num_eval_examples, + shuffle_input_data=False) + model = skip_thoughts_model.SkipThoughtsModel(model_config, mode="eval") + model.build() + + losses = tf.concat(model.target_cross_entropy_losses, 0) + weights = tf.concat(model.target_cross_entropy_loss_weights, 0) + + # Create the Saver to restore model Variables. + saver = tf.train.Saver() + + # Create the summary operation and the summary writer. + summary_op = tf.summary.merge_all() + summary_writer = tf.summary.FileWriter(eval_dir) + + g.finalize() + + # Run a new evaluation run every eval_interval_secs. + while True: + start = time.time() + tf.logging.info("Starting evaluation at " + time.strftime( + "%Y-%m-%d-%H:%M:%S", time.localtime())) + run_once(model, losses, weights, saver, summary_writer, summary_op) + time_to_next_eval = start + FLAGS.eval_interval_secs - time.time() + if time_to_next_eval > 0: + time.sleep(time_to_next_eval) + + +if __name__ == "__main__": + tf.app.run() diff --git a/skip_thoughts/train.py b/skip_thoughts/train.py new file mode 100644 index 0000000..e7c18d2 --- /dev/null +++ b/skip_thoughts/train.py @@ -0,0 +1,245 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +# Changes by Babylon Partners +# - Added +# --run_dir +# --pretrained_word_emb_file +# --word_emb_trainable +# --skipgram_encoder +# --decoder +# --normalise_decoder_losses +# --skipgram_prefactor +# --sequence_prefactor +# ============================================================================== +"""Train the skip-thoughts model.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import cPickle +import json +import os +import time + +import tensorflow as tf + +from skip_thoughts import configuration +from skip_thoughts import experiments +from skip_thoughts import skip_thoughts_model + +FLAGS = tf.flags.FLAGS + +# Data +tf.flags.DEFINE_string("input_file_pattern", None, + "File pattern of sharded TFRecord files containing " + "tf.Example protos.") + +# Training dir +tf.flags.DEFINE_string("run_dir", None, + "Directory where all of the runs are.") +tf.flags.DEFINE_string("train_dir", None, + "Directory for training. Overwrites autogenerated " + "train_dir.") + +# Vocabulary config +tf.flags.DEFINE_integer("vocab_size", 20000, + "Size of the vocabulary") + + +# Word embedding config +tf.flags.DEFINE_integer("word_dim", 620, + "Dimensionality of the word embeddings") +tf.flags.DEFINE_string("pretrained_word_emb_file", None, + "File containing pre-trained word embeddings," + "such as word2vec") +tf.flags.DEFINE_bool("word_emb_trainable", False, + "Whether pre-trained word embeddings are" + "jointly trainable with the model.") + +# Encoder config +tf.flags.DEFINE_integer("encoder_dim", 2400, + "The number of units to use in encoder and decoder" + "rnn cells.") +tf.flags.DEFINE_bool("skipgram_encoder", False, + "Whether to use a skipgram encoder (sum of embeddings)" + "instead of sequence encoder (RNN)") + +# Decoder config +tf.flags.DEFINE_string("decoder", None, + "Decoder specification in SEQxSKGy format, " + "where x, y can be 0, 1, 2, and 3." + "SEQ stands for sequence (recurrent) decoder " + "and SKG stands for bag-of-words (BOW) decoder." + "0 - no decoder of this type is present" + "1 - decoder for the current sentence (Autoencoder)" + "2 - decoders for the previous and next sentences " + "(Skip-Though/FastSent style)" + "3 - decoders for previous, current, and next sentences" + "(Skip-Thought + Autoencoder)" + "Note that it is possible to combine SEQ and SKG") +tf.flags.DEFINE_bool("share_weights_logits", True, + "Whether to tie the weights in the output layer of the " + "decoder") +tf.flags.DEFINE_bool("normalise_decoder_losses", False, + "Whether to normalise the losses of the decoders. If " + "True, this divides each sequence loss by the number" + "of sequence decoders, and the skipgram " + "decoder losses by the number of skipgram decoders.") +tf.flags.DEFINE_float("skipgram_prefactor", 1., + "Constant to multiply each skipgram loss with.") +tf.flags.DEFINE_float("sequence_prefactor", 1., + "Constant to multiply each SEQ loss with.") + +# Training config +tf.flags.DEFINE_integer("number_of_steps", 500000, + "The number of steps to take.") +tf.flags.DEFINE_float("gpu_fraction", 1.0, + "What fraction of the gpu to use") +tf.flags.DEFINE_integer("batch_size", 128, + "Batch size") + +tf.logging.set_verbosity(tf.logging.INFO) + + +def _setup_learning_rate(config, global_step): + """Sets up the learning rate with optional exponential decay. + + Args: + config: Object containing learning rate configuration parameters. + global_step: Tensor; the global step. + + Returns: + learning_rate: Tensor; the learning rate with exponential decay. + """ + if config.learning_rate_decay_factor > 0: + learning_rate = tf.train.exponential_decay( + learning_rate=float(config.learning_rate), + global_step=global_step, + decay_steps=config.learning_rate_decay_steps, + decay_rate=config.learning_rate_decay_factor, + staircase=False) + else: + learning_rate = tf.constant(config.learning_rate) + return learning_rate + + +def write_config(train_dir, flags): + flags_path = os.path.join(train_dir, 'flags.pkl') + configs_pkl_path = os.path.join(train_dir, 'config.pkl') + configs_pkl_json = os.path.join(train_dir, 'config.json') + + tf.logging.info("Writing out flags to {p}.".format( + p=flags_path)) + with open(flags_path, 'w') as f: + cPickle.dump(flags, f) + + tf.logging.info("Writing out config dict to {p}.".format( + p=configs_pkl_path)) + with open(configs_pkl_path, 'w') as f: + cPickle.dump(flags.__flags, f) + + tf.logging.info("Writing out config json to {p}.".format( + p=configs_pkl_json)) + with open(configs_pkl_json, 'w') as f: + json.dump(flags.__flags, f) + + return -1 + + +def main(unused_argv): + if not FLAGS.input_file_pattern: + raise ValueError("--input_file_pattern is required.") + if not FLAGS.run_dir: + raise ValueError("--run_dir is required.") + if not FLAGS.decoder: + raise ValueError("--decoder is required.") + + if not FLAGS.train_dir: + train_dir = os.path.join( + FLAGS.run_dir, 'run_{t}'.format(t=time.time())) + tf.logging.info("No specified --train_dir. Creating {d}.".format( + d=train_dir)) + os.makedirs(train_dir) + + write_config(train_dir=train_dir, flags=FLAGS) + + else: + tf.logging.info("Specified --train_dir {d}; Not autocreating.".format( + d=FLAGS.train_dir)) + train_dir = FLAGS.train_dir + + decoder_config = experiments.get_decoder_config(flags=FLAGS) + model_config = configuration.model_config( + input_file_pattern=FLAGS.input_file_pattern, + vocab_size=FLAGS.vocab_size, + batch_size=FLAGS.batch_size, + word_embedding_dim=FLAGS.word_dim, + pretrained_word_emb_file=FLAGS.pretrained_word_emb_file, + word_emb_trainable=FLAGS.word_emb_trainable, + encoder_dim=FLAGS.encoder_dim, + skipgram_encoder=FLAGS.skipgram_encoder, + sequence_decoder_pre=decoder_config.sequence_decoder_pre, + sequence_decoder_cur=decoder_config.sequence_decoder_cur, + sequence_decoder_post=decoder_config.sequence_decoder_post, + skipgram_decoder_pre=decoder_config.skipgram_decoder_pre, + skipgram_decoder_cur=decoder_config.skipgram_decoder_cur, + skipgram_decoder_post=decoder_config.skipgram_decoder_post, + share_weights_logits=FLAGS.share_weights_logits, + normalise_decoder_losses=FLAGS.normalise_decoder_losses, + skipgram_prefactor=FLAGS.skipgram_prefactor, + sequence_prefactor=FLAGS.sequence_prefactor) + training_config = configuration.training_config( + number_of_steps=FLAGS.number_of_steps) + + tf.logging.info("Building training graph.") + g = tf.Graph() + with g.as_default(): + tf.set_random_seed(1234) + model = skip_thoughts_model.SkipThoughtsModel( + model_config, mode="train") + model.build() + + learning_rate = _setup_learning_rate( + training_config, model.global_step) + optimizer = tf.train.AdamOptimizer(learning_rate) + + train_tensor = tf.contrib.slim.learning.create_train_op( + total_loss=model.total_loss, + optimizer=optimizer, + global_step=model.global_step, + clip_gradient_norm=training_config.clip_gradient_norm, + summarize_gradients=True, + check_numerics=True) + + saver = tf.train.Saver() + + gpu_options = tf.GPUOptions( + per_process_gpu_memory_fraction=FLAGS.gpu_fraction) + + tf.contrib.slim.learning.train( + train_op=train_tensor, + logdir=train_dir, + graph=g, + global_step=model.global_step, + number_of_steps=training_config.number_of_steps, + session_config=tf.ConfigProto(gpu_options=gpu_options), + save_summaries_secs=training_config.save_summaries_secs, + saver=saver, + save_interval_secs=training_config.save_model_secs) + + +if __name__ == "__main__": + tf.app.run() diff --git a/skip_thoughts/vocabulary_expansion.py b/skip_thoughts/vocabulary_expansion.py new file mode 100644 index 0000000..a215431 --- /dev/null +++ b/skip_thoughts/vocabulary_expansion.py @@ -0,0 +1,203 @@ +# Copyright 2017 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Compute an expanded vocabulary of embeddings using a word2vec model. + +This script loads the word embeddings from a trained skip-thoughts model and +from a trained word2vec model (typically with a larger vocabulary). It trains a +linear regression model without regularization to learn a linear mapping from +the word2vec embedding space to the skip-thoughts embedding space. The model is +then applied to all words in the word2vec vocabulary, yielding vectors in the +skip-thoughts word embedding space for the union of the two vocabularies. + +The linear regression task is to learn a parameter matrix W to minimize + || X - Y * W ||^2, +where X is a matrix of skip-thoughts embeddings of shape [num_words, dim1], +Y is a matrix of word2vec embeddings of shape [num_words, dim2], and W is a +matrix of shape [dim2, dim1]. + +This is based on the "Translation Matrix" method from the paper: + + "Exploiting Similarities among Languages for Machine Translation" + Tomas Mikolov, Quoc V. Le, Ilya Sutskever + https://arxiv.org/abs/1309.4168 +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import collections +import os.path + + +import gensim.models +import numpy as np +import sklearn.linear_model +import tensorflow as tf + +FLAGS = tf.flags.FLAGS + +tf.flags.DEFINE_string("skip_thoughts_model", None, + "Checkpoint file or directory containing a checkpoint " + "file.") + +tf.flags.DEFINE_string("skip_thoughts_vocab", None, + "Path to vocabulary file containing a list of newline-" + "separated words where the word id is the " + "corresponding 0-based index in the file.") + +tf.flags.DEFINE_string("word2vec_model", None, + "File containing a word2vec model in binary format.") + +tf.flags.DEFINE_string("output_dir", None, "Output directory.") + +tf.logging.set_verbosity(tf.logging.INFO) + + +def _load_skip_thoughts_embeddings(checkpoint_path): + """Loads the embedding matrix from a skip-thoughts model checkpoint. + + Args: + checkpoint_path: Model checkpoint file or directory containing a checkpoint + file. + + Returns: + word_embedding: A numpy array of shape [vocab_size, embedding_dim]. + + Raises: + ValueError: If no checkpoint file matches checkpoint_path. + """ + if tf.gfile.IsDirectory(checkpoint_path): + checkpoint_file = tf.train.latest_checkpoint(checkpoint_path) + if not checkpoint_file: + raise ValueError("No checkpoint file found in %s" % checkpoint_path) + else: + checkpoint_file = checkpoint_path + + tf.logging.info("Loading skip-thoughts embedding matrix from %s", + checkpoint_file) + reader = tf.train.NewCheckpointReader(checkpoint_file) + word_embedding = reader.get_tensor("word_embedding") + tf.logging.info("Loaded skip-thoughts embedding matrix of shape %s", + word_embedding.shape) + + return word_embedding + + +def _load_vocabulary(filename): + """Loads a vocabulary file. + + Args: + filename: Path to text file containing newline-separated words. + + Returns: + vocab: A dictionary mapping word to word id. + """ + tf.logging.info("Reading vocabulary from %s", filename) + vocab = collections.OrderedDict() + with tf.gfile.GFile(filename, mode="r") as f: + for i, line in enumerate(f): + word = line.strip().decode("utf-8") + assert word not in vocab, "Attempting to add word twice: %s" % word + vocab[word] = i + tf.logging.info("Read vocabulary of size %d", len(vocab)) + return vocab + + +def _expand_vocabulary(skip_thoughts_emb, skip_thoughts_vocab, word2vec): + """Runs vocabulary expansion on a skip-thoughts model using a word2vec model. + + Args: + skip_thoughts_emb: A numpy array of shape [skip_thoughts_vocab_size, + skip_thoughts_embedding_dim]. + skip_thoughts_vocab: A dictionary of word to id. + word2vec: An instance of gensim.models.KeyedVectors. + + Returns: + combined_emb: A dictionary mapping words to embedding vectors. + """ + # Find words shared between the two vocabularies. + tf.logging.info("Finding shared words") + shared_words = [w for w in word2vec.vocab if w in skip_thoughts_vocab] + + # Select embedding vectors for shared words. + tf.logging.info("Selecting embeddings for %d shared words", len(shared_words)) + shared_st_emb = skip_thoughts_emb[[ + skip_thoughts_vocab[w] for w in shared_words + ]] + shared_w2v_emb = word2vec[shared_words] + + # Train a linear regression model on the shared embedding vectors. + tf.logging.info("Training linear regression model") + model = sklearn.linear_model.LinearRegression() + model.fit(shared_w2v_emb, shared_st_emb) + + # Create the expanded vocabulary. + tf.logging.info("Creating embeddings for expanded vocabuary") + combined_emb = collections.OrderedDict() + for w in word2vec.vocab: + # Ignore words with underscores (spaces). + if "_" not in w: + w_emb = model.predict(word2vec[w].reshape(1, -1)) + combined_emb[w] = w_emb.reshape(-1) + + for w in skip_thoughts_vocab: + combined_emb[w] = skip_thoughts_emb[skip_thoughts_vocab[w]] + + tf.logging.info("Created expanded vocabulary of %d words", len(combined_emb)) + + return combined_emb + + +def main(unused_argv): + if not FLAGS.skip_thoughts_model: + raise ValueError("--skip_thoughts_model is required.") + if not FLAGS.skip_thoughts_vocab: + raise ValueError("--skip_thoughts_vocab is required.") + if not FLAGS.word2vec_model: + raise ValueError("--word2vec_model is required.") + if not FLAGS.output_dir: + raise ValueError("--output_dir is required.") + + if not tf.gfile.IsDirectory(FLAGS.output_dir): + tf.gfile.MakeDirs(FLAGS.output_dir) + + # Load the skip-thoughts embeddings and vocabulary. + skip_thoughts_emb = _load_skip_thoughts_embeddings(FLAGS.skip_thoughts_model) + skip_thoughts_vocab = _load_vocabulary(FLAGS.skip_thoughts_vocab) + + # Load the Word2Vec model. + word2vec = gensim.models.KeyedVectors.load_word2vec_format( + FLAGS.word2vec_model, binary=True) + + # Run vocabulary expansion. + embedding_map = _expand_vocabulary(skip_thoughts_emb, skip_thoughts_vocab, + word2vec) + + # Save the output. + vocab = embedding_map.keys() + vocab_file = os.path.join(FLAGS.output_dir, "vocab.txt") + with tf.gfile.GFile(vocab_file, "w") as f: + f.write("\n".join(vocab)) + tf.logging.info("Wrote vocabulary file to %s", vocab_file) + + embeddings = np.array(embedding_map.values()) + embeddings_file = os.path.join(FLAGS.output_dir, "embeddings.npy") + np.save(embeddings_file, embeddings) + tf.logging.info("Wrote embeddings file to %s", embeddings_file) + + +if __name__ == "__main__": + tf.app.run() diff --git a/unrolling_the_decoder.md b/unrolling_the_decoder.md new file mode 100644 index 0000000..1179416 --- /dev/null +++ b/unrolling_the_decoder.md @@ -0,0 +1,115 @@ +# Unrolling the Decoder + +## Introduction + +As discussed in the decoding decoders paper, the optimal space for an RNN plus softmax projection is +obtained by unrolling the decocer and using the concatentation of its hidden states as the +representation of the input (see figure below). +![Unrolling an RNN Decoder](/images/unroll.png) + +## Code + +In order use the decoder at inference time, in contrast to the original [TensorFlow SkipThoughts implementation](https://github.com/tensorflow/models/tree/master/research/skip_thoughts), we need to load the entire graph. + +First, we load the encoder. + +```{python} +flags.data_dir = ... +flags.uni_vocab_file = ... +flags.uni_embeddings_file = ... +flags.uni_checkpoint_path = ... +flags.decoder = ... + +decoder_config = experiments.get_decoder_config(flags=flags) + +uni_config = configuration.model_config( + sequence_decoder_pre=decoder_config.sequence_decoder_pre, + sequence_decoder_cur=decoder_config.sequence_decoder_cur, + sequence_decoder_post=decoder_config.sequence_decoder_post, + skipgram_decoder_pre=decoder_config.skipgram_decoder_pre, + skipgram_decoder_cur=decoder_config.skipgram_decoder_cur, + skipgram_decoder_post=decoder_config.skipgram_decoder_post) + +encoder = encoder_manager.EncoderManager() + +encoder.load_model(uni_config, + flags.uni_vocab_file, + flags.uni_embeddings_file, + flags.uni_checkpoint_path, + mode='encode-decode') +``` +We then pull the graph and session object from the encoder +```{python} +g, sess = encoder.graph, encoder.sessions[0] +``` +In order to perform the unrolling, we need the names of tensors involed in the unrolling process. +To help you, if tracking the names of tensors is diffcult, you can always modify the architecture post-training in such +a way that data-flow tensors aquire a speific name using `tf.identity` for example: +```{python} +tensor_to_name = tf.identity(tensor_to_name, name='name_of_tensor_to_name') +``` +Now this tensor can be accessed using the `get_tensor_by_name(...)` method of the `tf.Graph`. +In this case, the tensor would acquire the name `name_of_tensor_to_name:0` since it is the zero-th tensor produced +by the `tf.identity` op named `name_of_tensor_to_name`. + +For each decoder we need the following tensors: ++ The logits (for example `decoder_pre_logits:0`) ++ The decoder output (for example `decoder_pre_output:0`) ++ The decoder state (for example `decoder_pre_state:0`) +as well as the word embedding matrix, for example `word_embedding:0`. + +Using these, we can define dictionaries of the tensors necessary for the unrolling - one global dictionary, and one specific to each decoder +``` +tensor_names_global = { + 'word_embedding': 'word_embedding:0'} + +tensor_names_pre = { + 'logits': 'decoder_pre_logits:0', + 'decoder_output': 'decoder_pre_output:0', + 'decoder_state': 'decoder_pre_state:0'} + +tensor_names_post = { + 'logits': 'decoder_post_logits:0', + 'decoder_output': 'decoder_post_output:0', + 'decoder_state': 'decoder_post_state:0'} +``` +To build the decoders, we use these dictionaries to creeate instances of the [Decoder class](/skip_thoughts/decode.py) +``` +decoder_pre = decode.Decoder( + g=g, + tensor_names_decoder=tensor_names_pre, + tensor_names_global=tensor_names_global) + +decoder_post = decode.Decoder( + g=g, + tensor_names_decoder=tensor_names_post, + tensor_names_global=tensor_names_global) +``` +With this setup, we can now do some unrolling. +``` +batch_size = 2 +unroll_steps = 5 + +data = [ + "and wow", + "hey !", + "what's this thing suddenly coming towards me very fast ?", + "very very fast" + "so big and flat and round , it needs a big wide sounding name like ow ound round ground !" + "that's it !" + "that's a good name – ground !" + "i wonder if it will be friends with me ?"] + +decode_pre_rep, decode_post_rep = decode.decode( + sess=sess, data=data, + encoder=encoder, decoder_pre=decoder_pre, decoder_post=decoder_post, + batch_size=batch_size, use_norm=True, steps=unroll_steps) +``` +The vector representations `decode_pre_rep` and `decode_post_rep` are the unrolled representations for the prev and post decoders respectively. They are aligned in sentences, and can be concatenated to produce a single representation +``` +decode_rep_concat = np.concatenate( + (np.array(decode_pre_rep), np.array(decode_post_rep)), axis=1) +``` +which can then be used for downstream tasks, such as similarity and transfer. + +