├── .github └── workflows │ └── pythonpackage.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── bin ├── fetch_lample_embedding.py ├── parse_CoNLL2003.py └── prepare_embeddings.py ├── config ├── external │ ├── conll2003.glove.yaml │ ├── conll2003.skipngram.yaml │ ├── conll2003.yaml │ └── cpc1.0.yaml ├── iteration │ ├── long.yaml │ ├── mid.yaml │ └── short.yaml ├── model │ ├── lample.yaml │ └── simple-lstm-crf.yaml ├── optimizer │ ├── adabound.yaml │ ├── adam.yaml │ └── sgd_with_clipping.yaml ├── preprocessing │ └── znorm.yaml └── training │ ├── conll2003.lample.glove.yaml │ ├── conll2003.lample.skipngram.adabound.yaml │ ├── conll2003.lample.skipngram.yaml │ ├── conll2003.lample.yaml │ ├── conll2003.simple-lstm-crf.yaml │ └── cpc1.0.lample.yaml ├── data └── .gitkeep ├── docs └── CPC1.0.md ├── model └── .gitkeep ├── poetry.lock ├── pyner ├── __init__.py ├── named_entity │ ├── __init__.py │ ├── corpus.py │ ├── dataset.py │ ├── evaluator.py │ ├── inference.py │ ├── nn.py │ ├── recognizer.py │ ├── tagger.py │ └── train.py └── util │ ├── __init__.py │ ├── config.py │ ├── deterministic.py │ ├── iterator.py │ ├── metric.py │ ├── optimizer.py │ └── vocab.py ├── pyproject.toml ├── setup.cfg ├── static └── image │ └── pyner.png └── tests ├── named_entity ├── test_corpus.py └── test_dataset.py └── util ├── test_data └── v1 │ └── vocab.words.txt └── test_vocab.py /.github/workflows/pythonpackage.yml: -------------------------------------------------------------------------------- 1 | name: Python package 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | max-parallel: 4 11 | matrix: 12 | python-version: [3.6, 3.7] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Set up Python ${{ matrix.python-version }} 17 | uses: actions/setup-python@v1 18 | with: 19 | python-version: ${{ matrix.python-version }} 20 | - name: Install dependencies 21 | run: | 22 | python -m pip install --upgrade pip 23 | pip install . 24 | - name: Lint with flake8 25 | run: | 26 | pip install flake8 27 | # stop the build if there are Python syntax errors or undefined names 28 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 29 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 30 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 31 | - name: Test with pytest 32 | run: | 33 | pip install pytest 34 | pytest 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # emacs 2 | *~ 3 | 4 | # compiled 5 | *.pyc 6 | 7 | # IntelliJ 8 | .idea 9 | *.iml 10 | 11 | # model 12 | model 13 | 14 | # data 15 | data 16 | 17 | # notebook 18 | notebook/.ipynb_checkpoints 19 | 20 | # kytea model, which are now included 21 | # *.knm 22 | 23 | /data/external 24 | /prediction 25 | 26 | .* 27 | !.gitignore 28 | 29 | build 30 | dist 31 | *.egg-info 32 | 33 | /script/conlleval 34 | 35 | /cover 36 | 37 | /tool/conlleval 38 | 39 | /model 40 | /model.* 41 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cuda:10.2-cudnn8-devel-ubuntu18.04 2 | 3 | ENV LANG C.UTF-8 4 | ENV LC_ALL C.UTF-8 5 | ENV PYTHONIOENCODING UTF-8 6 | 7 | RUN apt-get update && apt-get install -y --no-install-recommends \ 8 | build-essential language-pack-ja \ 9 | python3 python3-dev python3-pip python3-setuptools \ 10 | curl tmux sudo git && \ 11 | apt-get clean && \ 12 | rm -rf /var/lib/apt/lists/* 13 | 14 | RUN pip3 install pip --upgrade 15 | RUN pip3 install setuptools --upgrade 16 | RUN pip3 install poetry 17 | 18 | WORKDIR /work 19 | COPY pyproject.toml . 20 | COPY poetry.lock . 21 | COPY pyner ./pyner 22 | RUN poetry install 23 | 24 | WORKDIR /tmp 25 | RUN curl https://www.clips.uantwerpen.be/conll2000/chunking/conlleval.txt > conlleval 26 | RUN chmod 777 conlleval 27 | 28 | WORKDIR /work 29 | COPY data ./data 30 | COPY config ./config 31 | 32 | COPY bin ./bin 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2019 himkt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export TAG='himkt/pyner:latest' 2 | 3 | 4 | .PHONY: build start test lint 5 | 6 | build: 7 | docker build -t $(TAG) . 8 | 9 | start: 10 | docker run --gpus all --rm -it $(TAG) 11 | 12 | test: 13 | poetry run python -m pytest tests 14 | 15 | lint: 16 | poetry run flake8 pyner 17 | 18 | get-glove: 19 | mkdir -p data/external/GloveEmbeddings 20 | mkdir -p data/processed/GloveEmbeddings 21 | cd data/external/GloveEmbeddings && wget http://nlp.stanford.edu/data/glove.6B.zip 22 | cd data/external/GloveEmbeddings && unzip glove.6B.zip 23 | cd data/external/GloveEmbeddings && rm glove.6B.zip 24 | poetry run python bin/prepare_embeddings.py \ 25 | data/external/GloveEmbeddings/glove.6B.100d.txt \ 26 | data/processed/GloveEmbeddings/glove.6B.100d \ 27 | --format glove 28 | 29 | get-lample: 30 | rm -rf data/external/GloveEmbeddings 31 | mkdir -p data/external/LampleEmbeddings 32 | mkdir -p data/processed/LampleEmbeddings 33 | poetry run python bin/fetch_lample_embedding.py 34 | poetry run python bin/prepare_embeddings.py \ 35 | data/external/LampleEmbeddings/skipngram_100d.txt \ 36 | data/processed/LampleEmbeddings/skipngram_100d \ 37 | --format word2vec 38 | 39 | get-conlleval: 40 | curl https://www.clips.uantwerpen.be/conll2000/chunking/conlleval.txt > conlleval 41 | chmod 777 conlleval 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | # PyNER: Toolkit for sequence labeling in Chainer 5 | 6 | [![CircleCI](https://circleci.com/gh/himkt/pyner.svg?style=svg)](https://circleci.com/gh/himkt/pyner) 7 | [![GitHub stars](https://img.shields.io/github/stars/himkt/pyner.svg?maxAge=2592000&colorB=blue)](https://github.com/himkt/pyner/stargazers) 8 | [![GitHub issues](https://img.shields.io/github/issues/himkt/pyner.svg?colorB=red)](https://github.com/himkt/pyner/issues) 9 | [![GitHub release](https://img.shields.io/github/release/himkt/pyner.svg?maxAge=2592000&colorB=yellow)](https://github.com/himkt/pyner) 10 | [![MIT License](http://img.shields.io/badge/license-MIT-green.svg?style=flat)](LICENSE) 11 | 12 | PyNER is a sequence labeling toolkit that allows researcher and developer to 13 | train/evaluate neural sequence labeling methods. 14 | 15 | 16 | # QuickStart 17 | 18 | You can try `pyner` on a local machine or a docker container. 19 | 20 | ## 1. Local Machine 21 | 22 | - setup (If you do not install [pipenv](https://github.com/pypa/pipenv), please install) 23 | 24 | ``` 25 | poetry install 26 | ``` 27 | 28 | - train 29 | 30 | ``` 31 | # If a GPU is not available, specify `--device -1` 32 | pipenv run python pyner/named_entity/train.py config/training/conll2003.lample.yaml --device 0 33 | ``` 34 | 35 | ## 2. Docker container 36 | 37 | - build container 38 | 39 | ``` 40 | make build 41 | ``` 42 | 43 | - launch container 44 | 45 | ``` 46 | make start 47 | ``` 48 | 49 | - train 50 | 51 | You have to execute this command in Docker container. 52 | 53 | ``` 54 | # If a GPU is not available, specify `--device -1` 55 | python3 train.py config/training/conll2003.lample.yaml --device 0 56 | ``` 57 | 58 | This experiment uses CoNLL 2003 dataset. 59 | Please read the following "Prepare dataset" section. 60 | 61 | 62 | # Prepare dataset 63 | 64 | We use a data format same as [deep-crf](https://github.com/aonotas/deep-crf). 65 | 66 | ``` 67 | $ head -n 15 data/processed/CoNLL2003_BIOES/train.txt 68 | EU S-ORG 69 | rejects O 70 | German S-MISC 71 | call O 72 | to O 73 | boycott O 74 | British S-MISC 75 | lamb O 76 | . O 77 | 78 | Peter B-PER 79 | Blackburn E-PER 80 | 81 | BRUSSELS S-LOC 82 | 1996-08-22 O 83 | ``` 84 | 85 | For reproducing results in [Lample's paper](https://aclweb.org/anthology/N16-1030), 86 | you have to do some step to prepare datasets. 87 | 88 | ## 1. Prepare CoNLL 2003 Dataset 89 | 90 | We can't include CoNLL 2003 dataset in this repository due to legal limitation. 91 | Instead, PyNER offers the way to create dataset from CoNLL 2003 dataset 92 | 93 | If you could prepare CoNLL 2003 dataset, you would have three files like below. 94 | 95 | - eng.iob.testa 96 | - eng.iob.testb 97 | - eng.iob.train 98 | 99 | Please put them to on same directoy (e.g. `data/external/CoNLL2003`). 100 | 101 | ``` 102 | $ tree data/external/CoNLL2003 103 | data/external/CoNLL2003 104 | ├── eng.iob.testa 105 | ├── eng.iob.testb 106 | └── eng.iob.train 107 | ``` 108 | 109 | Then, you can create the dataset for pyner by following command. 110 | After running the command, `./data/processed/CoNLL2003` will be generated for you. 111 | 112 | ``` 113 | $ python bin/parse_CoNLL2003.py \ 114 | --data-dir data/external/CoNLL2003 \ 115 | --output-dir data/processed/CoNLL2003 \ 116 | --convert-rule iob2bio 117 | 2019-09-24 23:43:39,299 INFO root :create dataset for CoNLL2003 118 | 2019-09-24 23:43:39,299 INFO root :create corpus parser 119 | 2019-09-24 23:43:39,300 INFO root :parsing corpus for training 120 | 2019-09-24 23:44:02,240 INFO root :parsing corpus for validating 121 | 2019-09-24 23:44:04,397 INFO root :parsing corpus for testing 122 | 2019-09-24 23:44:06,507 INFO root :Create train dataset 123 | 2019-09-24 23:44:06,705 INFO root :Create valid dataset 124 | 2019-09-24 23:44:06,755 INFO root :Create test dataset 125 | 2019-09-24 23:44:06,800 INFO root :Create vocabulary 126 | $ 127 | $ tree data/processed/CoNLL2003 128 | data/processed/CoNLL2003 129 | ├── test.txt 130 | ├── train.txt 131 | ├── valid.txt 132 | ├── vocab.chars.txt 133 | ├── vocab.tags.txt 134 | └── vocab.words.txt 135 | ``` 136 | 137 | 138 | ## 2. Prepare pre-trained Word Embeddings used in Lample's paper 139 | 140 | Using pre-trained word embeddings significantly improve the performance of NER. 141 | Lample et al. also use pre-trained word embeddings. 142 | They use Skip-N-Gram embeddings, which can be downloaded from [Official repo's issue]. 143 | To use this, please run `make get-lample` before running `make build`. 144 | (If you want to use GloVe embeddings, please run `make get-glove`.) 145 | 146 | ``` 147 | $ make get-lample 148 | rm -rf data/external/GloveEmbeddings 149 | mkdir -p data/external/LampleEmbeddings 150 | mkdir -p data/processed/LampleEmbeddings 151 | python bin/fetch_lample_embedding.py 152 | python bin/prepare_embeddings.py \ 153 | data/external/LampleEmbeddings/skipngram_100d.txt \ 154 | data/processed/LampleEmbeddings/skipngram_100d \ 155 | --format word2vec 156 | saved model 157 | $ 158 | $ ls -1 data/processed/LampleEmbeddings 159 | skipngram_100d 160 | skipngram_100d.vectors.npy 161 | ``` 162 | 163 | Congratulations! All preparation steps have done. 164 | Now you can train the Lample's LSTM-CRF. 165 | Please run the command: 166 | - Local machine: `python3 pyner/named_entity/train.py config/training/conll2003.lample.yaml --device 0` 167 | - Docker container: `python3 train.py config/training/conll2003.lample.yaml --device 0` 168 | 169 | 170 | # Inference and Evaluate 171 | 172 | You can test your model using `pyner/named_entity/inference.py`. 173 | Only thing you have to pass to `inference.py` is path to model dir. 174 | Model dir is defined in config file (**output**). 175 | 176 | ``` 177 | $ cat config/training/conll2003.lample.yaml 178 | iteration: "./config/iteration/long.yaml" 179 | external: "./config/external/conll2003.yaml" 180 | model: "./config/model/lample.yaml" 181 | optimizer: "./config/optimizer/sgd_with_clipping.yaml" 182 | preprocessing: "./config/preprocessing/znorm.yaml" 183 | output: "./model/conll2003.lample" # model dir is here!! 184 | ``` 185 | 186 | If you successfully train the model, some files are generated on `model/conll2003.lample.skipngram.YYYY-MM-DDTxx:xx:xx.xxxxxx`. 187 | 188 | ``` 189 | $ ls -1 model/conll2003.lample.skipngram.2019-09-24T07:02:33.536822 190 | args 191 | log 192 | snapshot_epoch_0001 193 | snapshot_epoch_0002 194 | snapshot_epoch_0003 195 | snapshot_epoch_0004 196 | ... 197 | snapshot_epoch_0148 198 | snapshot_epoch_0149 199 | snapshot_epoch_0150 200 | validation.main.fscore.epoch_031.pred # here!! 201 | ``` 202 | 203 | Running `python3 pyner/named_entity/inference.py` will generate prediction results on `model/conll2003.lample.skipngram.YYYY-MM-DDTxx:xx:xx.xxxxxx` 204 | A file name would be `{metrics}.epoch_{xxx}.pred`. 205 | `inference.py` check a log and select a model which achieve most high f1 score on development set. 206 | You can use other selection criteria such as watching loss value and specifying an epoch. 207 | 208 | - Dev loss: `python3 pyner/named_entity/inference.py --metrics validation/main/loss model/conll2003.lample.skipngram.2019-09-24T07:02:33.536822`) 209 | - Specific epoch: `python3 pyner/named_entity/inference.py --epoch 1 model/conll2003.lample.skipngram.2019-09-24T07:02:33.536822` 210 | 211 | If you could generate a prediction file, it's time to evaluate a model performance. 212 | [conlleval](https://www.clips.uantwerpen.be/conll2000/chunking/output.html) is the standard script to evaluate CoNLL Chunking/NER tasks. 213 | First of all, we have to download `conlleval`. 214 | Running the command `make get-conlleval` would download `conlleval` on current directory. 215 | Then, evaluate!!! 216 | 217 | ``` 218 | $ ./conlleval < model/conll2003.lample.skipngram.2019-09-24T07:02:33.536822/validation.main.fscore.epoch_139.pred 219 | processed 46435 tokens with 5628 phrases; found: 5651 phrases; correct: 5134. 220 | accuracy: 97.82%; precision: 90.85%; recall: 91.22%; FB1: 91.04 221 | LOC: precision: 93.41%; recall: 92.18%; FB1: 92.79 1640 222 | MISC: precision: 80.66%; recall: 80.66%; FB1: 80.66 693 223 | ORG: precision: 88.72%; recall: 89.79%; FB1: 89.26 1676 224 | PER: precision: 94.76%; recall: 96.23%; FB1: 95.49 1642 225 | ``` 226 | 227 | F1 score on test set is 91.04, which is approximately the same as the result in Lample's paper! (90.94) 228 | 229 | 230 | ### Reference 231 | - [Neural Architectures for Named Entity Recognition] 232 | - NAACL2016, Lample et al. 233 | 234 | 235 | [Neural Architectures for Named Entity Recognition]: https://aclweb.org/anthology/N16-1030 236 | [Official repo's issue]: https://github.com/glample/tagger/issues/44 237 | [CoNLL 2003]: https://www.clips.uantwerpen.be/conll2003/ner/ 238 | -------------------------------------------------------------------------------- /bin/fetch_lample_embedding.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import re 3 | 4 | import requests 5 | 6 | 7 | def download_file_from_google_drive(): 8 | URL = "https://drive.google.com{}" 9 | 10 | file_id = "0B23ji47zTOQNUXYzbUVhdDN2ZmM" 11 | session = requests.Session() 12 | 13 | target_url = URL.format("/uc?export=download") 14 | response = session.get(target_url, params={"id": file_id}) 15 | content = response.content.decode("utf-8") # NOQA 16 | pattern = re.compile('') 17 | 18 | result = re.search(pattern, content) 19 | params = result.group(1) 20 | params = params.replace("amp;", "") 21 | 22 | target_url = URL.format(params) 23 | response = session.get(target_url, cookies=response.cookies, stream=True) 24 | save_response_content(response) 25 | 26 | 27 | def save_response_content(response): 28 | cur_length = 0 29 | chunk_size = 32768 30 | 31 | skipngram_path = pathlib.Path("data/external/LampleEmbeddings") 32 | with open(skipngram_path / "skipngram_100d.txt", "wb") as f: 33 | for chunk in response.iter_content(chunk_size): 34 | if chunk: # filter out keep-alive new chunks 35 | cur_length += len(chunk) 36 | cur_mbytes = cur_length / 1024 ** 2 37 | print(f"downloaded: {cur_mbytes:.4f} MB\r", end="") 38 | f.write(chunk) 39 | 40 | 41 | if __name__ == "__main__": 42 | download_file_from_google_drive() 43 | -------------------------------------------------------------------------------- /bin/parse_CoNLL2003.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pathlib 3 | 4 | import click 5 | 6 | from pyner.named_entity.corpus import CorpusParser 7 | from pyner.named_entity.corpus import enum 8 | from pyner.named_entity.corpus import write_sentences 9 | from pyner.named_entity.corpus import write_vocab 10 | 11 | SEED = 42 12 | BOS = 0 # begin of step 13 | EOS = 1 # end of step 14 | XXX = 2 # other 15 | 16 | 17 | @click.command() 18 | @click.option("--data-dir", default="./data/external/CoNLL2003", type=str) 19 | @click.option("--output-dir", default="./data/processed/CoNLL2003", type=str) 20 | @click.option("--convert-rule", default="iob2bio", type=str) 21 | @click.option("--delimiter", default=r" +", type=str) 22 | def main(data_dir: str, output_dir: str, convert_rule: str, delimiter: str): 23 | logging.info("create dataset for CoNLL2003") 24 | 25 | data_path = pathlib.Path(data_dir) 26 | output_path = pathlib.Path(output_dir) 27 | output_path.mkdir(exist_ok=True, parents=True) 28 | 29 | logging.info("create corpus parser") 30 | corpus_parser = CorpusParser(convert_rule, delimiter) 31 | 32 | logging.info("parsing corpus for training") 33 | train_word_sentences, train_tag_sentences = corpus_parser.parse_file( 34 | data_path / "eng.iob.train", word_idx=0 35 | ) 36 | train_words, train_chars, train_tags = enum( 37 | train_word_sentences, train_tag_sentences 38 | ) 39 | 40 | logging.info("parsing corpus for validating") 41 | valid_word_sentences, valid_tag_sentences = corpus_parser.parse_file( # NOQA 42 | data_path / "eng.iob.testa", word_idx=0 43 | ) 44 | _, _, valid_tags = enum(valid_word_sentences, valid_tag_sentences) 45 | 46 | logging.info("parsing corpus for testing") 47 | test_word_sentences, test_tag_sentences = corpus_parser.parse_file( 48 | data_path / "eng.iob.testb", word_idx=0 49 | ) 50 | _, _, test_tags = enum(test_word_sentences, test_tag_sentences) 51 | 52 | for mode in ["train", "valid", "test"]: 53 | if mode == "train": 54 | sentences = list( 55 | zip( 56 | train_word_sentences, 57 | train_tag_sentences, 58 | ) 59 | ) 60 | elif mode == "valid": 61 | sentences = list( 62 | zip( 63 | valid_word_sentences, 64 | valid_tag_sentences, 65 | ) 66 | ) 67 | elif mode == "test": 68 | sentences = list( 69 | zip( 70 | test_word_sentences, 71 | test_tag_sentences, 72 | ) 73 | ) 74 | 75 | logging.info("Create %s dataset", mode) 76 | write_sentences(mode, sentences, output_path) 77 | 78 | # NOTE create vocabularies only using training dataset 79 | logging.info("Create vocabulary") 80 | vocab, char_vocab = train_words, train_chars 81 | tag_vocab = train_tags + valid_tags + test_tags 82 | write_vocab("words", vocab, output_path) 83 | write_vocab("chars", char_vocab, output_path) 84 | write_vocab("tags", tag_vocab, output_path) 85 | 86 | 87 | if __name__ == "__main__": 88 | fmt = "%(asctime)s %(levelname)s %(name)s :%(message)s" 89 | logging.basicConfig(level=logging.DEBUG, format=fmt) 90 | main() 91 | -------------------------------------------------------------------------------- /bin/prepare_embeddings.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | 3 | import click 4 | 5 | from gensim.models import KeyedVectors 6 | from gensim.scripts.glove2word2vec import glove2word2vec 7 | 8 | 9 | @click.command() 10 | @click.argument("input_file", type=str) # NOQA 11 | @click.argument("output_file", type=str) 12 | @click.option("--format", default="word2vec", type=str) 13 | def main(input_file: str, output_file: str, format: str): 14 | input_file = pathlib.Path(input_file) # NOQA 15 | output_file = pathlib.Path(output_file) 16 | 17 | if format == "glove": 18 | tmp_file = "/tmp/w2v.tmp" 19 | glove2word2vec(input_file, tmp_file) 20 | model = KeyedVectors.load_word2vec_format(tmp_file) 21 | print("loaded GloVe embeddings") 22 | 23 | elif format == "word2vec": 24 | model = KeyedVectors.load_word2vec_format(input_file) 25 | print("loaded Word2vec embeddings") 26 | 27 | model.save(output_file.as_posix()) 28 | print("saved model") 29 | 30 | 31 | if __name__ == "__main__": 32 | main() 33 | -------------------------------------------------------------------------------- /config/external/conll2003.glove.yaml: -------------------------------------------------------------------------------- 1 | # training data 2 | data_dir: "./data/processed/CoNLL2003" 3 | 4 | # pre-trained word vectors 5 | word_vector: "./data/processed/GloveEmbeddings/glove.6B.100d" 6 | 7 | # [optional] specify the way to merge the two vocabularies 8 | # 1: vocabulary consists of words appear in training data 9 | # 2: vocabulary consists of words exists in pre-trained word vectors 10 | vocab_merge_operator: "union" 11 | -------------------------------------------------------------------------------- /config/external/conll2003.skipngram.yaml: -------------------------------------------------------------------------------- 1 | # training data 2 | data_dir: "./data/processed/CoNLL2003" 3 | 4 | # pre-trained word vectors 5 | word_vector: "./data/processed/LampleEmbeddings/skipngram_100d" 6 | 7 | # [optional] specify the way to merge the two vocabularies 8 | # 1: vocabulary consists of words appear in training data 9 | # 2: vocabulary consists of words exists in pre-trained word vectors 10 | vocab_merge_operator: "union" 11 | -------------------------------------------------------------------------------- /config/external/conll2003.yaml: -------------------------------------------------------------------------------- 1 | # training data 2 | data_dir: "./data/processed/CoNLL2003" 3 | -------------------------------------------------------------------------------- /config/external/cpc1.0.yaml: -------------------------------------------------------------------------------- 1 | # training data 2 | data_dir: "./data/processed/CPC1.0" 3 | -------------------------------------------------------------------------------- /config/iteration/long.yaml: -------------------------------------------------------------------------------- 1 | batch_size: 10 2 | epoch: 300 3 | -------------------------------------------------------------------------------- /config/iteration/mid.yaml: -------------------------------------------------------------------------------- 1 | batch_size: 10 2 | epoch: 100 3 | -------------------------------------------------------------------------------- /config/iteration/short.yaml: -------------------------------------------------------------------------------- 1 | batch_size: 10 2 | epoch: 50 3 | -------------------------------------------------------------------------------- /config/model/lample.yaml: -------------------------------------------------------------------------------- 1 | word_dim: 100 2 | word_hidden_dim: 100 3 | char_dim: 25 4 | char_hidden_dim: 25 5 | dropout: 0.5 6 | -------------------------------------------------------------------------------- /config/model/simple-lstm-crf.yaml: -------------------------------------------------------------------------------- 1 | word_dim: 100 2 | word_hidden_dim: 100 3 | dropout: 0.5 4 | -------------------------------------------------------------------------------- /config/optimizer/adabound.yaml: -------------------------------------------------------------------------------- 1 | name: 'AdaBound' 2 | alpha: 0.001 3 | beta1: 0.99 4 | beta2: 0.99 5 | final_lr: 0.01 6 | 7 | gradient_clipping: 5.0 8 | -------------------------------------------------------------------------------- /config/optimizer/adam.yaml: -------------------------------------------------------------------------------- 1 | name: 'Adam' 2 | alpha: 0.001 3 | beta1: 0.99 4 | beta2: 0.99 5 | -------------------------------------------------------------------------------- /config/optimizer/sgd_with_clipping.yaml: -------------------------------------------------------------------------------- 1 | name: 'SGD' 2 | learning_rate: 0.01 3 | 4 | gradient_clipping: 5.0 5 | -------------------------------------------------------------------------------- /config/preprocessing/znorm.yaml: -------------------------------------------------------------------------------- 1 | replace_zero: true 2 | lower: false 3 | -------------------------------------------------------------------------------- /config/training/conll2003.lample.glove.yaml: -------------------------------------------------------------------------------- 1 | external: "./config/external/conll2003.glove.yaml" 2 | iteration: "./config/iteration/long.yaml" 3 | model: "./config/model/lample.yaml" 4 | optimizer: "./config/optimizer/sgd_with_clipping.yaml" 5 | preprocessing: "./config/preprocessing/znorm.yaml" 6 | output: "./model/conll2003.lample.globe" 7 | -------------------------------------------------------------------------------- /config/training/conll2003.lample.skipngram.adabound.yaml: -------------------------------------------------------------------------------- 1 | external: "./config/external/conll2003.skipngram.yaml" 2 | iteration: "./config/iteration/long.yaml" 3 | model: "./config/model/lample.yaml" 4 | optimizer: "./config/optimizer/adabound.yaml" 5 | preprocessing: "./config/preprocessing/znorm.yaml" 6 | output: "./model/conll2003.lample.skipngram.adabound" 7 | -------------------------------------------------------------------------------- /config/training/conll2003.lample.skipngram.yaml: -------------------------------------------------------------------------------- 1 | external: "./config/external/conll2003.skipngram.yaml" 2 | iteration: "./config/iteration/long.yaml" 3 | model: "./config/model/lample.yaml" 4 | optimizer: "./config/optimizer/sgd_with_clipping.yaml" 5 | preprocessing: "./config/preprocessing/znorm.yaml" 6 | output: "./model/conll2003.lample.skipngram" 7 | -------------------------------------------------------------------------------- /config/training/conll2003.lample.yaml: -------------------------------------------------------------------------------- 1 | iteration: "./config/iteration/long.yaml" 2 | external: "./config/external/conll2003.yaml" 3 | model: "./config/model/lample.yaml" 4 | optimizer: "./config/optimizer/sgd_with_clipping.yaml" 5 | preprocessing: "./config/preprocessing/znorm.yaml" 6 | output: "./model/conll2003.lample" 7 | -------------------------------------------------------------------------------- /config/training/conll2003.simple-lstm-crf.yaml: -------------------------------------------------------------------------------- 1 | iteration: "./config/iteration/long.yaml" 2 | external: "./config/external/conll2003.yaml" 3 | model: "./config/model/simple-lstm-crf.yaml" 4 | optimizer: "./config/optimizer/sgd_with_clipping.yaml" 5 | preprocessing: "./config/preprocessing/znorm.yaml" 6 | output: "./model/conll2003.simple-lstm-crf" 7 | -------------------------------------------------------------------------------- /config/training/cpc1.0.lample.yaml: -------------------------------------------------------------------------------- 1 | iteration: "./config/iteration/long.yaml" 2 | external: "./config/external/cpc1.0.yaml" 3 | model: "./config/model/lample.yaml" 4 | optimizer: "./config/optimizer/sgd_with_clipping.yaml" 5 | preprocessing: "./config/preprocessing/znorm.yaml" 6 | output: "./model/cpc1.0.lample" 7 | -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himkt/pyner/91371db03bbe7d621f76281c9a26affac00e8034/data/.gitkeep -------------------------------------------------------------------------------- /docs/CPC1.0.md: -------------------------------------------------------------------------------- 1 | # Cookpad Parsed Corpus v1.0 2 | 3 | You can train a BiLSTM-CRF model used in the paper of Cookpad Parsed Corpus (CPC1.0). 4 | Note that you have to run `make conll2003` on the [CPC1.0 repository](https://github.com/cookpad/cpc1.0) in advance. 5 | 6 | 7 | ## Put CPC1.0 8 | 9 | ```sh 10 | mv `path_to_CPC_repository`/outputs/conll2003 data/external/CPC1.0 11 | ``` 12 | 13 | 14 | ## Create dataset 15 | 16 | ```sh 17 | poetry run python bin/parse_CoNLL2003.py \ 18 | --delimiter "\t" \ 19 | --data-dir data/external/CPC1.0 \ 20 | --output-dir data/processed/CPC1.0 21 | ``` 22 | 23 | 24 | ## Build an image 25 | 26 | ```sh 27 | docker build -t himkt/pyner . 28 | ``` 29 | 30 | 31 | ## Train a model 32 | 33 | ```sh 34 | docker run \ 35 | -v `pwd`/model:/work/model \ 36 | --gpus all \ 37 | -it \ 38 | --rm himkt/pyner \ 39 | poetry run python pyner/named_entity/train.py \ 40 | config/training/cpc1.0.lample.yaml \ 41 | --device 0 \ 42 | --seed 24 43 | ``` 44 | 45 | 46 | ## Inference 47 | 48 | ```sh 49 | docker run \ 50 | -v `pwd`/model:/work/model \ 51 | --gpus all \ 52 | -it \ 53 | --rm himkt/pyner \ 54 | poetry run python pyner/named_entity/inference.py \ 55 | --metric validation/main/fscore \ 56 | model/cpc1.0.lample.`timestamp_of_your_model` 57 | ``` 58 | 59 | 60 | # Reference 61 | 62 | - Harashima and Hiramatsu, [Cookpad Parsed Corpus: Linguistic Annotations of Japanese Recipes](https://www.aclweb.org/anthology/2020.law-1.8/), LAW, 2020. 63 | -------------------------------------------------------------------------------- /model/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himkt/pyner/91371db03bbe7d621f76281c9a26affac00e8034/model/.gitkeep -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "alembic" 3 | version = "1.4.3" 4 | description = "A database migration tool for SQLAlchemy." 5 | category = "main" 6 | optional = false 7 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 8 | 9 | [package.dependencies] 10 | Mako = "*" 11 | python-dateutil = "*" 12 | python-editor = ">=0.3" 13 | SQLAlchemy = ">=1.1.0" 14 | 15 | [[package]] 16 | name = "appdirs" 17 | version = "1.4.4" 18 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 19 | category = "dev" 20 | optional = false 21 | python-versions = "*" 22 | 23 | [[package]] 24 | name = "atomicwrites" 25 | version = "1.4.0" 26 | description = "Atomic file writes." 27 | category = "dev" 28 | optional = false 29 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 30 | 31 | [[package]] 32 | name = "attrs" 33 | version = "20.3.0" 34 | description = "Classes Without Boilerplate" 35 | category = "dev" 36 | optional = false 37 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 38 | 39 | [package.extras] 40 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] 41 | docs = ["furo", "sphinx", "zope.interface"] 42 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 43 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] 44 | 45 | [[package]] 46 | name = "black" 47 | version = "20.8b1" 48 | description = "The uncompromising code formatter." 49 | category = "dev" 50 | optional = false 51 | python-versions = ">=3.6" 52 | 53 | [package.dependencies] 54 | appdirs = "*" 55 | click = ">=7.1.2" 56 | dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} 57 | mypy-extensions = ">=0.4.3" 58 | pathspec = ">=0.6,<1" 59 | regex = ">=2020.1.8" 60 | toml = ">=0.10.1" 61 | typed-ast = ">=1.4.0" 62 | typing-extensions = ">=3.7.4" 63 | 64 | [package.extras] 65 | colorama = ["colorama (>=0.4.3)"] 66 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 67 | 68 | [[package]] 69 | name = "certifi" 70 | version = "2020.12.5" 71 | description = "Python package for providing Mozilla's CA Bundle." 72 | category = "main" 73 | optional = false 74 | python-versions = "*" 75 | 76 | [[package]] 77 | name = "cffi" 78 | version = "1.14.4" 79 | description = "Foreign Function Interface for Python calling C code." 80 | category = "main" 81 | optional = false 82 | python-versions = "*" 83 | 84 | [package.dependencies] 85 | pycparser = "*" 86 | 87 | [[package]] 88 | name = "chainer" 89 | version = "7.7.0" 90 | description = "A flexible framework of neural networks" 91 | category = "main" 92 | optional = false 93 | python-versions = ">=3.5.0" 94 | 95 | [package.dependencies] 96 | filelock = "*" 97 | numpy = ">=1.9.0" 98 | protobuf = ">=3.0.0" 99 | six = ">=1.9.0" 100 | typing_extensions = "*" 101 | 102 | [package.extras] 103 | appveyor = ["pytest (<4.2.0)", "attrs (<19.2.0)", "mock", "pytest-timeout (<1.3.0)"] 104 | docs = ["sphinx (==1.8.2)", "sphinx-rtd-theme", "onnx (<1.7.0)", "packaging"] 105 | doctest = ["sphinx (==1.8.2)", "matplotlib", "theano"] 106 | jenkins = ["pytest (<4.2.0)", "attrs (<19.2.0)", "mock", "pytest-timeout (<1.3.0)", "pytest-cov", "nose", "coveralls", "codecov"] 107 | stylecheck = ["autopep8 (>=1.4.1,<1.5)", "flake8 (>=3.7,<3.8)", "pycodestyle (>=2.5,<2.6)"] 108 | test = ["pytest (<4.2.0)", "attrs (<19.2.0)", "mock"] 109 | 110 | [[package]] 111 | name = "chainerui" 112 | version = "0.11.0" 113 | description = "ChainerUI: User Interface for Chainer" 114 | category = "main" 115 | optional = false 116 | python-versions = "*" 117 | 118 | [package.dependencies] 119 | alembic = ">=1.0.0" 120 | filelock = ">=3.0.9" 121 | Flask = ">=1.1.0" 122 | gevent = ">=1.2.2" 123 | msgpack = ">=0.5.6" 124 | sqlalchemy = ">=1.1.18" 125 | structlog = ">=18.2.0" 126 | urllib3 = ">=1.24.1" 127 | 128 | [package.extras] 129 | docs = ["chainer (>=3.0.0)"] 130 | doctest = ["sphinx (==1.8.2)"] 131 | stylecheck = ["autopep8", "hacking"] 132 | test = ["numpy", "pytest (>=4.0.0,<5.0.0)", "mock"] 133 | test-ci = ["autopep8", "hacking", "numpy", "pytest (>=4.0.0,<5.0.0)", "mock", "pytest-cov", "coveralls", "sphinx (==1.8.2)", "pillow", "matplotlib", "scipy", "chainer"] 134 | test-ci-contrib = ["autopep8", "hacking", "numpy", "pytest (>=4.0.0,<5.0.0)", "mock", "pytest-cov", "coveralls", "sphinx (==1.8.2)", "pillow", "matplotlib", "scipy", "chainer", "pytorch-ignite"] 135 | test-ci-plain = ["autopep8", "hacking", "numpy", "pytest (>=4.0.0,<5.0.0)", "mock", "pytest-cov", "coveralls"] 136 | 137 | [[package]] 138 | name = "chardet" 139 | version = "4.0.0" 140 | description = "Universal encoding detector for Python 2 and 3" 141 | category = "main" 142 | optional = false 143 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 144 | 145 | [[package]] 146 | name = "click" 147 | version = "7.1.2" 148 | description = "Composable command line interface toolkit" 149 | category = "main" 150 | optional = false 151 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 152 | 153 | [[package]] 154 | name = "colorama" 155 | version = "0.4.4" 156 | description = "Cross-platform colored terminal text." 157 | category = "dev" 158 | optional = false 159 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 160 | 161 | [[package]] 162 | name = "cupy-cuda102" 163 | version = "7.8.0" 164 | description = "CuPy: NumPy-like API accelerated with CUDA" 165 | category = "main" 166 | optional = false 167 | python-versions = ">=3.5.0" 168 | 169 | [package.dependencies] 170 | fastrlock = ">=0.3" 171 | numpy = ">=1.9.0" 172 | six = ">=1.9.0" 173 | 174 | [package.extras] 175 | appveyor = ["pytest (<4.2.0)", "attrs (<19.2.0)", "mock"] 176 | docs = ["sphinx (==3.0.4)", "sphinx-rtd-theme"] 177 | doctest = ["matplotlib"] 178 | jenkins = ["pytest (<4.2.0)", "attrs (<19.2.0)", "mock", "pytest-timeout", "pytest-cov", "coveralls", "codecov"] 179 | setup = ["fastrlock (>=0.3)"] 180 | stylecheck = ["autopep8 (==1.4.4)", "flake8 (==3.7.9)", "pbr (==4.0.4)", "pycodestyle (==2.5.0)"] 181 | test = ["pytest (<4.2.0)", "attrs (<19.2.0)", "mock"] 182 | travis = ["autopep8 (==1.4.4)", "flake8 (==3.7.9)", "pbr (==4.0.4)", "pycodestyle (==2.5.0)", "sphinx (==3.0.4)", "sphinx-rtd-theme"] 183 | 184 | [[package]] 185 | name = "cython" 186 | version = "0.29.14" 187 | description = "The Cython compiler for writing C extensions for the Python language." 188 | category = "main" 189 | optional = false 190 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 191 | 192 | [[package]] 193 | name = "dataclasses" 194 | version = "0.8" 195 | description = "A backport of the dataclasses module for Python 3.6" 196 | category = "dev" 197 | optional = false 198 | python-versions = ">=3.6, <3.7" 199 | 200 | [[package]] 201 | name = "fastrlock" 202 | version = "0.5" 203 | description = "Fast, re-entrant optimistic lock implemented in Cython" 204 | category = "main" 205 | optional = false 206 | python-versions = "*" 207 | 208 | [[package]] 209 | name = "filelock" 210 | version = "3.0.12" 211 | description = "A platform independent file lock." 212 | category = "main" 213 | optional = false 214 | python-versions = "*" 215 | 216 | [[package]] 217 | name = "flake8" 218 | version = "3.8.4" 219 | description = "the modular source code checker: pep8 pyflakes and co" 220 | category = "dev" 221 | optional = false 222 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" 223 | 224 | [package.dependencies] 225 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 226 | mccabe = ">=0.6.0,<0.7.0" 227 | pycodestyle = ">=2.6.0a1,<2.7.0" 228 | pyflakes = ">=2.2.0,<2.3.0" 229 | 230 | [[package]] 231 | name = "flask" 232 | version = "1.1.2" 233 | description = "A simple framework for building complex web applications." 234 | category = "main" 235 | optional = false 236 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 237 | 238 | [package.dependencies] 239 | click = ">=5.1" 240 | itsdangerous = ">=0.24" 241 | Jinja2 = ">=2.10.1" 242 | Werkzeug = ">=0.15" 243 | 244 | [package.extras] 245 | dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] 246 | docs = ["sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] 247 | dotenv = ["python-dotenv"] 248 | 249 | [[package]] 250 | name = "gensim" 251 | version = "3.8.3" 252 | description = "Python framework for fast Vector Space Modelling" 253 | category = "main" 254 | optional = false 255 | python-versions = "*" 256 | 257 | [package.dependencies] 258 | Cython = "0.29.14" 259 | numpy = ">=1.11.3" 260 | scipy = ">=0.18.1" 261 | six = ">=1.5.0" 262 | smart-open = ">=1.8.1" 263 | 264 | [package.extras] 265 | distributed = ["Pyro4 (>=4.27)"] 266 | docs = ["pytest", "pytest-rerunfailures", "mock", "cython", "nmslib", "pyemd", "testfixtures", "Morfessor (==2.0.2a4)", "python-Levenshtein (>=0.10.2)", "visdom (>0.1.8.7)", "scikit-learn", "Pyro4 (>=4.27)", "sphinx (<=2.4.4)", "sphinx-gallery", "sphinxcontrib.programoutput", "sphinxcontrib-napoleon", "matplotlib", "plotly", "memory-profiler", "annoy", "pyro4", "nltk", "statsmodels", "pandas"] 267 | test = ["pytest", "pytest-rerunfailures", "mock", "cython", "nmslib", "pyemd", "testfixtures", "Morfessor (==2.0.2a4)", "python-Levenshtein (>=0.10.2)", "visdom (>0.1.8.7)", "scikit-learn"] 268 | test-win = ["pytest", "pytest-rerunfailures", "mock", "cython", "nmslib", "pyemd", "testfixtures", "Morfessor (==2.0.2a4)", "python-Levenshtein (>=0.10.2)", "visdom (>0.1.8.7)", "scikit-learn"] 269 | 270 | [[package]] 271 | name = "gevent" 272 | version = "20.12.1" 273 | description = "Coroutine-based network library" 274 | category = "main" 275 | optional = false 276 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" 277 | 278 | [package.dependencies] 279 | cffi = {version = ">=1.12.2", markers = "platform_python_implementation == \"CPython\" and sys_platform == \"win32\""} 280 | greenlet = {version = ">=0.4.17,<2.0", markers = "platform_python_implementation == \"CPython\""} 281 | "zope.event" = "*" 282 | "zope.interface" = "*" 283 | 284 | [package.extras] 285 | dnspython = ["dnspython (>=1.16.0,<2.0)", "idna"] 286 | docs = ["repoze.sphinx.autointerface", "sphinxcontrib-programoutput"] 287 | monitor = ["psutil (>=5.7.0)"] 288 | recommended = ["dnspython (>=1.16.0,<2.0)", "idna", "cffi (>=1.12.2)", "selectors2", "backports.socketpair", "psutil (>=5.7.0)"] 289 | test = ["dnspython (>=1.16.0,<2.0)", "idna", "requests", "objgraph", "cffi (>=1.12.2)", "selectors2", "futures", "mock", "backports.socketpair", "contextvars (==2.4)", "coverage (>=5.0)", "coveralls (>=1.7.0)", "psutil (>=5.7.0)"] 290 | 291 | [[package]] 292 | name = "greenlet" 293 | version = "0.4.17" 294 | description = "Lightweight in-process concurrent programming" 295 | category = "main" 296 | optional = false 297 | python-versions = "*" 298 | 299 | [[package]] 300 | name = "idna" 301 | version = "2.10" 302 | description = "Internationalized Domain Names in Applications (IDNA)" 303 | category = "main" 304 | optional = false 305 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 306 | 307 | [[package]] 308 | name = "importlib-metadata" 309 | version = "3.3.0" 310 | description = "Read metadata from Python packages" 311 | category = "dev" 312 | optional = false 313 | python-versions = ">=3.6" 314 | 315 | [package.dependencies] 316 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 317 | zipp = ">=0.5" 318 | 319 | [package.extras] 320 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 321 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] 322 | 323 | [[package]] 324 | name = "iniconfig" 325 | version = "1.1.1" 326 | description = "iniconfig: brain-dead simple config-ini parsing" 327 | category = "dev" 328 | optional = false 329 | python-versions = "*" 330 | 331 | [[package]] 332 | name = "itsdangerous" 333 | version = "1.1.0" 334 | description = "Various helpers to pass data to untrusted environments and back." 335 | category = "main" 336 | optional = false 337 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 338 | 339 | [[package]] 340 | name = "jinja2" 341 | version = "2.11.3" 342 | description = "A very fast and expressive template engine." 343 | category = "main" 344 | optional = false 345 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 346 | 347 | [package.dependencies] 348 | MarkupSafe = ">=0.23" 349 | 350 | [package.extras] 351 | i18n = ["Babel (>=0.8)"] 352 | 353 | [[package]] 354 | name = "joblib" 355 | version = "1.0.0" 356 | description = "Lightweight pipelining with Python functions" 357 | category = "main" 358 | optional = false 359 | python-versions = ">=3.6" 360 | 361 | [[package]] 362 | name = "mako" 363 | version = "1.1.3" 364 | description = "A super-fast templating language that borrows the best ideas from the existing templating languages." 365 | category = "main" 366 | optional = false 367 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 368 | 369 | [package.dependencies] 370 | MarkupSafe = ">=0.9.2" 371 | 372 | [package.extras] 373 | babel = ["babel"] 374 | lingua = ["lingua"] 375 | 376 | [[package]] 377 | name = "markupsafe" 378 | version = "1.1.1" 379 | description = "Safely add untrusted strings to HTML/XML markup." 380 | category = "main" 381 | optional = false 382 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" 383 | 384 | [[package]] 385 | name = "mccabe" 386 | version = "0.6.1" 387 | description = "McCabe checker, plugin for flake8" 388 | category = "dev" 389 | optional = false 390 | python-versions = "*" 391 | 392 | [[package]] 393 | name = "msgpack" 394 | version = "1.0.2" 395 | description = "MessagePack (de)serializer." 396 | category = "main" 397 | optional = false 398 | python-versions = "*" 399 | 400 | [[package]] 401 | name = "mypy" 402 | version = "0.790" 403 | description = "Optional static typing for Python" 404 | category = "dev" 405 | optional = false 406 | python-versions = ">=3.5" 407 | 408 | [package.dependencies] 409 | mypy-extensions = ">=0.4.3,<0.5.0" 410 | typed-ast = ">=1.4.0,<1.5.0" 411 | typing-extensions = ">=3.7.4" 412 | 413 | [package.extras] 414 | dmypy = ["psutil (>=4.0)"] 415 | 416 | [[package]] 417 | name = "mypy-extensions" 418 | version = "0.4.3" 419 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 420 | category = "dev" 421 | optional = false 422 | python-versions = "*" 423 | 424 | [[package]] 425 | name = "numpy" 426 | version = "1.19.4" 427 | description = "NumPy is the fundamental package for array computing with Python." 428 | category = "main" 429 | optional = false 430 | python-versions = ">=3.6" 431 | 432 | [[package]] 433 | name = "packaging" 434 | version = "20.8" 435 | description = "Core utilities for Python packages" 436 | category = "dev" 437 | optional = false 438 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 439 | 440 | [package.dependencies] 441 | pyparsing = ">=2.0.2" 442 | 443 | [[package]] 444 | name = "pathspec" 445 | version = "0.8.1" 446 | description = "Utility library for gitignore style pattern matching of file paths." 447 | category = "dev" 448 | optional = false 449 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 450 | 451 | [[package]] 452 | name = "pluggy" 453 | version = "0.13.1" 454 | description = "plugin and hook calling mechanisms for python" 455 | category = "dev" 456 | optional = false 457 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 458 | 459 | [package.dependencies] 460 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 461 | 462 | [package.extras] 463 | dev = ["pre-commit", "tox"] 464 | 465 | [[package]] 466 | name = "protobuf" 467 | version = "3.14.0" 468 | description = "Protocol Buffers" 469 | category = "main" 470 | optional = false 471 | python-versions = "*" 472 | 473 | [package.dependencies] 474 | six = ">=1.9" 475 | 476 | [[package]] 477 | name = "py" 478 | version = "1.10.0" 479 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 480 | category = "dev" 481 | optional = false 482 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 483 | 484 | [[package]] 485 | name = "pycodestyle" 486 | version = "2.6.0" 487 | description = "Python style guide checker" 488 | category = "dev" 489 | optional = false 490 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 491 | 492 | [[package]] 493 | name = "pycparser" 494 | version = "2.20" 495 | description = "C parser in Python" 496 | category = "main" 497 | optional = false 498 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 499 | 500 | [[package]] 501 | name = "pyflakes" 502 | version = "2.2.0" 503 | description = "passive checker of Python programs" 504 | category = "dev" 505 | optional = false 506 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 507 | 508 | [[package]] 509 | name = "pyparsing" 510 | version = "2.4.7" 511 | description = "Python parsing module" 512 | category = "dev" 513 | optional = false 514 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 515 | 516 | [[package]] 517 | name = "pytest" 518 | version = "6.2.1" 519 | description = "pytest: simple powerful testing with Python" 520 | category = "dev" 521 | optional = false 522 | python-versions = ">=3.6" 523 | 524 | [package.dependencies] 525 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 526 | attrs = ">=19.2.0" 527 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 528 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 529 | iniconfig = "*" 530 | packaging = "*" 531 | pluggy = ">=0.12,<1.0.0a1" 532 | py = ">=1.8.2" 533 | toml = "*" 534 | 535 | [package.extras] 536 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 537 | 538 | [[package]] 539 | name = "python-dateutil" 540 | version = "2.8.1" 541 | description = "Extensions to the standard Python datetime module" 542 | category = "main" 543 | optional = false 544 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 545 | 546 | [package.dependencies] 547 | six = ">=1.5" 548 | 549 | [[package]] 550 | name = "python-editor" 551 | version = "1.0.4" 552 | description = "Programmatically open an editor, capture the result." 553 | category = "main" 554 | optional = false 555 | python-versions = "*" 556 | 557 | [[package]] 558 | name = "pyyaml" 559 | version = "5.3.1" 560 | description = "YAML parser and emitter for Python" 561 | category = "main" 562 | optional = false 563 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 564 | 565 | [[package]] 566 | name = "regex" 567 | version = "2020.11.13" 568 | description = "Alternative regular expression module, to replace re." 569 | category = "dev" 570 | optional = false 571 | python-versions = "*" 572 | 573 | [[package]] 574 | name = "requests" 575 | version = "2.25.1" 576 | description = "Python HTTP for Humans." 577 | category = "main" 578 | optional = false 579 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 580 | 581 | [package.dependencies] 582 | certifi = ">=2017.4.17" 583 | chardet = ">=3.0.2,<5" 584 | idna = ">=2.5,<3" 585 | urllib3 = ">=1.21.1,<1.27" 586 | 587 | [package.extras] 588 | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] 589 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 590 | 591 | [[package]] 592 | name = "scikit-learn" 593 | version = "0.24.0" 594 | description = "A set of python modules for machine learning and data mining" 595 | category = "main" 596 | optional = false 597 | python-versions = ">=3.6" 598 | 599 | [package.dependencies] 600 | joblib = ">=0.11" 601 | numpy = ">=1.13.3" 602 | scipy = ">=0.19.1" 603 | threadpoolctl = ">=2.0.0" 604 | 605 | [package.extras] 606 | benchmark = ["matplotlib (>=2.1.1)", "pandas (>=0.25.0)", "memory-profiler (>=0.57.0)"] 607 | docs = ["matplotlib (>=2.1.1)", "scikit-image (>=0.13)", "pandas (>=0.25.0)", "seaborn (>=0.9.0)", "memory-profiler (>=0.57.0)", "sphinx (>=3.2.0)", "sphinx-gallery (>=0.7.0)", "numpydoc (>=1.0.0)", "Pillow (>=7.1.2)", "sphinx-prompt (>=1.3.0)"] 608 | examples = ["matplotlib (>=2.1.1)", "scikit-image (>=0.13)", "pandas (>=0.25.0)", "seaborn (>=0.9.0)"] 609 | tests = ["matplotlib (>=2.1.1)", "scikit-image (>=0.13)", "pandas (>=0.25.0)", "pytest (>=5.0.1)", "pytest-cov (>=2.9.0)", "flake8 (>=3.8.2)", "mypy (>=0.770)", "pyamg (>=4.0.0)"] 610 | 611 | [[package]] 612 | name = "scipy" 613 | version = "1.5.4" 614 | description = "SciPy: Scientific Library for Python" 615 | category = "main" 616 | optional = false 617 | python-versions = ">=3.6" 618 | 619 | [package.dependencies] 620 | numpy = ">=1.14.5" 621 | 622 | [[package]] 623 | name = "seqeval" 624 | version = "1.2.2" 625 | description = "Testing framework for sequence labeling" 626 | category = "main" 627 | optional = false 628 | python-versions = "*" 629 | 630 | [package.dependencies] 631 | numpy = ">=1.14.0" 632 | scikit-learn = ">=0.21.3" 633 | 634 | [[package]] 635 | name = "six" 636 | version = "1.15.0" 637 | description = "Python 2 and 3 compatibility utilities" 638 | category = "main" 639 | optional = false 640 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 641 | 642 | [[package]] 643 | name = "smart-open" 644 | version = "4.0.1" 645 | description = "Utils for streaming large files (S3, HDFS, GCS, Azure Blob Storage, gzip, bz2...)" 646 | category = "main" 647 | optional = false 648 | python-versions = ">=3.6.*" 649 | 650 | [package.extras] 651 | all = ["boto3", "google-cloud-storage", "azure-storage-blob", "azure-common", "azure-core", "requests"] 652 | azure = ["azure-storage-blob", "azure-common", "azure-core"] 653 | gcp = ["google-cloud-storage"] 654 | http = ["requests"] 655 | s3 = ["boto3"] 656 | test = ["mock", "moto", "pathlib2", "responses", "boto3", "paramiko", "parameterizedtestcase", "pytest", "pytest-rerunfailures"] 657 | webhdfs = ["requests"] 658 | 659 | [[package]] 660 | name = "sqlalchemy" 661 | version = "1.3.22" 662 | description = "Database Abstraction Library" 663 | category = "main" 664 | optional = false 665 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 666 | 667 | [package.extras] 668 | mssql = ["pyodbc"] 669 | mssql_pymssql = ["pymssql"] 670 | mssql_pyodbc = ["pyodbc"] 671 | mysql = ["mysqlclient"] 672 | oracle = ["cx-oracle"] 673 | postgresql = ["psycopg2"] 674 | postgresql_pg8000 = ["pg8000"] 675 | postgresql_psycopg2binary = ["psycopg2-binary"] 676 | postgresql_psycopg2cffi = ["psycopg2cffi"] 677 | pymysql = ["pymysql"] 678 | 679 | [[package]] 680 | name = "structlog" 681 | version = "20.1.0" 682 | description = "Structured Logging for Python" 683 | category = "main" 684 | optional = false 685 | python-versions = "*" 686 | 687 | [package.dependencies] 688 | six = "*" 689 | 690 | [package.extras] 691 | azure-pipelines = ["coverage", "freezegun (>=0.2.8)", "pretend", "pytest (>=3.3.0)", "simplejson", "pytest-azurepipelines", "python-rapidjson", "pytest-asyncio"] 692 | dev = ["coverage", "freezegun (>=0.2.8)", "pretend", "pytest (>=3.3.0)", "simplejson", "sphinx", "twisted", "pre-commit", "python-rapidjson", "pytest-asyncio"] 693 | docs = ["sphinx", "twisted"] 694 | tests = ["coverage", "freezegun (>=0.2.8)", "pretend", "pytest (>=3.3.0)", "simplejson", "python-rapidjson", "pytest-asyncio"] 695 | 696 | [[package]] 697 | name = "threadpoolctl" 698 | version = "2.1.0" 699 | description = "threadpoolctl" 700 | category = "main" 701 | optional = false 702 | python-versions = ">=3.5" 703 | 704 | [[package]] 705 | name = "toml" 706 | version = "0.10.2" 707 | description = "Python Library for Tom's Obvious, Minimal Language" 708 | category = "dev" 709 | optional = false 710 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 711 | 712 | [[package]] 713 | name = "typed-ast" 714 | version = "1.4.1" 715 | description = "a fork of Python 2 and 3 ast modules with type comment support" 716 | category = "dev" 717 | optional = false 718 | python-versions = "*" 719 | 720 | [[package]] 721 | name = "typing-extensions" 722 | version = "3.7.4.3" 723 | description = "Backported and Experimental Type Hints for Python 3.5+" 724 | category = "main" 725 | optional = false 726 | python-versions = "*" 727 | 728 | [[package]] 729 | name = "urllib3" 730 | version = "1.26.4" 731 | description = "HTTP library with thread-safe connection pooling, file post, and more." 732 | category = "main" 733 | optional = false 734 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 735 | 736 | [package.extras] 737 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 738 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 739 | brotli = ["brotlipy (>=0.6.0)"] 740 | 741 | [[package]] 742 | name = "werkzeug" 743 | version = "1.0.1" 744 | description = "The comprehensive WSGI web application library." 745 | category = "main" 746 | optional = false 747 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 748 | 749 | [package.extras] 750 | dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] 751 | watchdog = ["watchdog"] 752 | 753 | [[package]] 754 | name = "zipp" 755 | version = "3.4.0" 756 | description = "Backport of pathlib-compatible object wrapper for zip files" 757 | category = "dev" 758 | optional = false 759 | python-versions = ">=3.6" 760 | 761 | [package.extras] 762 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 763 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] 764 | 765 | [[package]] 766 | name = "zope.event" 767 | version = "4.5.0" 768 | description = "Very basic event publishing system" 769 | category = "main" 770 | optional = false 771 | python-versions = "*" 772 | 773 | [package.extras] 774 | docs = ["sphinx"] 775 | test = ["zope.testrunner"] 776 | 777 | [[package]] 778 | name = "zope.interface" 779 | version = "5.2.0" 780 | description = "Interfaces for Python" 781 | category = "main" 782 | optional = false 783 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 784 | 785 | [package.extras] 786 | docs = ["sphinx", "repoze.sphinx.autointerface"] 787 | test = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] 788 | testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] 789 | 790 | [metadata] 791 | lock-version = "1.1" 792 | python-versions = "^3.6" 793 | content-hash = "5eb16d02fc599748dd46e4a251c58faf7ab3741c57c534284671cfa5cde0456e" 794 | 795 | [metadata.files] 796 | alembic = [ 797 | {file = "alembic-1.4.3-py2.py3-none-any.whl", hash = "sha256:4e02ed2aa796bd179965041afa092c55b51fb077de19d61835673cc80672c01c"}, 798 | {file = "alembic-1.4.3.tar.gz", hash = "sha256:5334f32314fb2a56d86b4c4dd1ae34b08c03cae4cb888bc699942104d66bc245"}, 799 | ] 800 | appdirs = [ 801 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 802 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 803 | ] 804 | atomicwrites = [ 805 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 806 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 807 | ] 808 | attrs = [ 809 | {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, 810 | {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, 811 | ] 812 | black = [ 813 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 814 | ] 815 | certifi = [ 816 | {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, 817 | {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, 818 | ] 819 | cffi = [ 820 | {file = "cffi-1.14.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775"}, 821 | {file = "cffi-1.14.4-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06"}, 822 | {file = "cffi-1.14.4-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26"}, 823 | {file = "cffi-1.14.4-cp27-cp27m-win32.whl", hash = "sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c"}, 824 | {file = "cffi-1.14.4-cp27-cp27m-win_amd64.whl", hash = "sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b"}, 825 | {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d"}, 826 | {file = "cffi-1.14.4-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca"}, 827 | {file = "cffi-1.14.4-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698"}, 828 | {file = "cffi-1.14.4-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b"}, 829 | {file = "cffi-1.14.4-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293"}, 830 | {file = "cffi-1.14.4-cp35-cp35m-win32.whl", hash = "sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2"}, 831 | {file = "cffi-1.14.4-cp35-cp35m-win_amd64.whl", hash = "sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7"}, 832 | {file = "cffi-1.14.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f"}, 833 | {file = "cffi-1.14.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362"}, 834 | {file = "cffi-1.14.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec"}, 835 | {file = "cffi-1.14.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b"}, 836 | {file = "cffi-1.14.4-cp36-cp36m-win32.whl", hash = "sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668"}, 837 | {file = "cffi-1.14.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009"}, 838 | {file = "cffi-1.14.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb"}, 839 | {file = "cffi-1.14.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d"}, 840 | {file = "cffi-1.14.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03"}, 841 | {file = "cffi-1.14.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01"}, 842 | {file = "cffi-1.14.4-cp37-cp37m-win32.whl", hash = "sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e"}, 843 | {file = "cffi-1.14.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35"}, 844 | {file = "cffi-1.14.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d"}, 845 | {file = "cffi-1.14.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b"}, 846 | {file = "cffi-1.14.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53"}, 847 | {file = "cffi-1.14.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e"}, 848 | {file = "cffi-1.14.4-cp38-cp38-win32.whl", hash = "sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d"}, 849 | {file = "cffi-1.14.4-cp38-cp38-win_amd64.whl", hash = "sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375"}, 850 | {file = "cffi-1.14.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909"}, 851 | {file = "cffi-1.14.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd"}, 852 | {file = "cffi-1.14.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a"}, 853 | {file = "cffi-1.14.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e"}, 854 | {file = "cffi-1.14.4-cp39-cp39-win32.whl", hash = "sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3"}, 855 | {file = "cffi-1.14.4-cp39-cp39-win_amd64.whl", hash = "sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b"}, 856 | {file = "cffi-1.14.4.tar.gz", hash = "sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c"}, 857 | ] 858 | chainer = [ 859 | {file = "chainer-7.7.0.tar.gz", hash = "sha256:efbe8d67138213f336566ecdc10357285dd7e18d5ca52fc0187df6189107d47b"}, 860 | ] 861 | chainerui = [ 862 | {file = "chainerui-0.11.0.tar.gz", hash = "sha256:c485b2867a82c8c6666e06c02b89bc5b1a553fc06a9af93f694c5b2f95695983"}, 863 | ] 864 | chardet = [ 865 | {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, 866 | {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, 867 | ] 868 | click = [ 869 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 870 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 871 | ] 872 | colorama = [ 873 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 874 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 875 | ] 876 | cupy-cuda102 = [ 877 | {file = "cupy_cuda102-7.8.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:03dfdb883cb3a039318b7934f5e4101a6c1d5aadf0c5873b2756df8473563ce7"}, 878 | {file = "cupy_cuda102-7.8.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:257cf9c2bcedbe4a5729066731d66d37652a0c411885cd10d97a1db1141785f4"}, 879 | {file = "cupy_cuda102-7.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9d5caa9d960c7f37aa1671523e48ae141bc6b34fc6081e5c9c16638ab103eeb9"}, 880 | {file = "cupy_cuda102-7.8.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1323e9f3f2610912816f9ac31c053f8e8be00180cec51ed5f76cbfb852734e7b"}, 881 | {file = "cupy_cuda102-7.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bad560eade7fd84881348c168c6b4a55cf0f511bc5fc94a87a27655f2c178d93"}, 882 | {file = "cupy_cuda102-7.8.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1599387e5e252c91ef7a131c7e790c7cc84e716cf005f09979076d6aaab032b5"}, 883 | {file = "cupy_cuda102-7.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:a9c5eff23c75ee1a764f37eb161da3a5488f068deb115e848da430d1edc962d8"}, 884 | ] 885 | cython = [ 886 | {file = "Cython-0.29.14-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:47e5e1502d52ef03387cf9d3b3241007961a84a466e58a3b74028e1dd4957f8c"}, 887 | {file = "Cython-0.29.14-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:1dcdaa319558eb924294a554dcf6c12383ec947acc7e779e8d3622409a7f7d28"}, 888 | {file = "Cython-0.29.14-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7bc18fc5a170f2c1cef5387a3d997c28942918bbee0f700e73fd2178ee8d474d"}, 889 | {file = "Cython-0.29.14-cp27-cp27m-win32.whl", hash = "sha256:89458b49976b1dee5d89ab4ac943da3717b4292bf624367e862e4ee172fcce99"}, 890 | {file = "Cython-0.29.14-cp27-cp27m-win_amd64.whl", hash = "sha256:c0b24bfe3431b3cb7ced323bca813dbd13aca973a1475b512d3331fd0de8ec60"}, 891 | {file = "Cython-0.29.14-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7f89eff20e4a7a64b55210dac17aea711ed8a3f2e78f2ff784c0e984302583dd"}, 892 | {file = "Cython-0.29.14-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:6c53338c1811f8c6d7f8cb7abd874810b15045e719e8207f957035c9177b4213"}, 893 | {file = "Cython-0.29.14-cp34-cp34m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:521340844cf388d109ceb61397f3fd5250ccb622a1a8e93559e8de76c80940a9"}, 894 | {file = "Cython-0.29.14-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:75c2dda47dcc3c77449712b1417bb6b89ec3b7b02e18c64262494dceffdf455e"}, 895 | {file = "Cython-0.29.14-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:05eb79efc8029d487251c8a2702a909a8ba33c332e06d2f3980866541bd81253"}, 896 | {file = "Cython-0.29.14-cp34-cp34m-win32.whl", hash = "sha256:1fc5bdda28f25fec44e4721677458aa509d743cd350862270309d61aa148d6ff"}, 897 | {file = "Cython-0.29.14-cp34-cp34m-win_amd64.whl", hash = "sha256:0c70e842e52e2f50cc43bad43b5e5bc515f30821a374e544abb0e0746f2350ff"}, 898 | {file = "Cython-0.29.14-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:094d28a34c3fa992ae02aea1edbe6ff89b3cc5870b6ee38b5baeb805dc57b013"}, 899 | {file = "Cython-0.29.14-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:280573a01d9348d44a42d6a9c651d9f7eb1fe9217df72555b2a118f902996a10"}, 900 | {file = "Cython-0.29.14-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:773c5a98e463b52f7e8197254b39b703a5ea1972aef3a94b3b921515d77dd041"}, 901 | {file = "Cython-0.29.14-cp35-cp35m-win32.whl", hash = "sha256:986f871c0fa649b293061236b93782d25c293a8dd8117c7ba05f8a61bdc261ae"}, 902 | {file = "Cython-0.29.14-cp35-cp35m-win_amd64.whl", hash = "sha256:78c3068dcba300d473fef57cdf523e34b37de522f5a494ef9ee1ac9b4b8bbe3f"}, 903 | {file = "Cython-0.29.14-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:f3818e578e687cdb21dc4aa4a3bc6278c656c9c393e9eda14dd04943f478863d"}, 904 | {file = "Cython-0.29.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:bb487881608ebd293592553c618f0c83316f4f13a64cb18605b1d2fb9fd3da3e"}, 905 | {file = "Cython-0.29.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:03f6bbb380ad0acb744fb06e42996ea217e9d00016ca0ff6f2e7d60f580d0360"}, 906 | {file = "Cython-0.29.14-cp36-cp36m-win32.whl", hash = "sha256:b8ab3ab38afc47d8f4fe629b836243544351cef681b6bdb1dc869028d6fdcbfb"}, 907 | {file = "Cython-0.29.14-cp36-cp36m-win_amd64.whl", hash = "sha256:298ceca7b0f0da4205fcb0b7c9ac9e120e2dafffd5019ba1618e84ef89434b5a"}, 908 | {file = "Cython-0.29.14-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:fe666645493d72712c46e4fbe8bec094b06aec3c337400479e9704439c9d9586"}, 909 | {file = "Cython-0.29.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4074a8bff0040035673cc6dd365a762476d6bff4d03d8ce6904e3e53f9a25dc8"}, 910 | {file = "Cython-0.29.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a14aa436586c41633339415de82a41164691d02d3e661038da533be5d40794a5"}, 911 | {file = "Cython-0.29.14-cp37-cp37m-win32.whl", hash = "sha256:41e7068e95fbf9ec94b41437f989caf9674135e770a39cdb9c00de459bafd1bc"}, 912 | {file = "Cython-0.29.14-cp37-cp37m-win_amd64.whl", hash = "sha256:05e8cfd3a3a6087aec49a1ae08a89171db991956209406d1e5576f9db70ece52"}, 913 | {file = "Cython-0.29.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e8fab9911fd2fa8e5af407057cb8bdf87762f983cba483fa3234be20a9a0af77"}, 914 | {file = "Cython-0.29.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d4039bb7f234ad32267c55e72fd49fb56078ea102f9d9d8559f6ec34d4887630"}, 915 | {file = "Cython-0.29.14-cp38-cp38-win32.whl", hash = "sha256:c7894c06205166d360ab2915ae306d1f7403e9ce3d3aaeff4095eaf98e42ce66"}, 916 | {file = "Cython-0.29.14-cp38-cp38-win_amd64.whl", hash = "sha256:a0f495a4fe5278aab278feee35e6102efecde5176a8a74dd28c28e3fc5c8d7c7"}, 917 | {file = "Cython-0.29.14.tar.gz", hash = "sha256:e4d6bb8703d0319eb04b7319b12ea41580df44fd84d83ccda13ea463c6801414"}, 918 | ] 919 | dataclasses = [ 920 | {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, 921 | {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, 922 | ] 923 | fastrlock = [ 924 | {file = "fastrlock-0.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:d92b85a8f609eea194a54978ccd97a385c6e78fb1ee86ae9dc07f1f50b225d9b"}, 925 | {file = "fastrlock-0.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:0111bd05a6f7c2a4005b4a847351454b66536d8320295c5505d41c360862b332"}, 926 | {file = "fastrlock-0.5-cp27-cp27m-win32.whl", hash = "sha256:b3bd1522cdf4203baa7822a8bfb441be22c7999456b89a640fcdce374d017649"}, 927 | {file = "fastrlock-0.5-cp27-cp27m-win_amd64.whl", hash = "sha256:d044d85bfc4aa7424507dfb13b600ccc77f9be75b3418801cf27810e836ce0bd"}, 928 | {file = "fastrlock-0.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:67e69f285484f1866ff7d4a61ab120fdda08d21e05c202e50c93c0b70bc4b906"}, 929 | {file = "fastrlock-0.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:3439d0e079005cb869f816522438b95023bf435e6851879adebe69cb1ec51801"}, 930 | {file = "fastrlock-0.5-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:bbd11d4ae58ee6b4500f8aea2489b5ea05a8855d3f8101faac20be73e02c67b0"}, 931 | {file = "fastrlock-0.5-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:6fc3ac4930e904b67db57677ecebc266b2e1801e362ff6a957c59ae380f146ac"}, 932 | {file = "fastrlock-0.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:f4400e572a23d81af9ae60841cf8d282c00b47afca66385ee5e7ce638dcb1bec"}, 933 | {file = "fastrlock-0.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a2c4dba6027bef685a4d8762e9f547496b81620103a303270ea7c459bcf7b19c"}, 934 | {file = "fastrlock-0.5-cp35-cp35m-win32.whl", hash = "sha256:70da964f1d4e1d88a9c6b52fad8b8c3f545449691de43fe29c44ff62a0284c70"}, 935 | {file = "fastrlock-0.5-cp35-cp35m-win_amd64.whl", hash = "sha256:3727e814e701a726d0a7390fb7ea37cb706971521f3f26f03382d1611a888734"}, 936 | {file = "fastrlock-0.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a9494ec76848a3fc9499732e23718ec5773adca0588da0e5c865eef7445854a5"}, 937 | {file = "fastrlock-0.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:79bc2fccafce7a6c43690cf3bfac4c6c76669e138312332a84619587e940d376"}, 938 | {file = "fastrlock-0.5-cp36-cp36m-win32.whl", hash = "sha256:dfafdf719612e06490ebe6c508fd38ab67ea63f69eea80249469e10d2605d583"}, 939 | {file = "fastrlock-0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:5cd0d96c7d7aeb87486d20463ddcb89e25e9cee63f99d1c981b381df724541f0"}, 940 | {file = "fastrlock-0.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:a923bc1b3d38d6899a2d3d8800e72df81c3f8d071a57db6f6cdeae22a2d2a7d1"}, 941 | {file = "fastrlock-0.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:20892428eacedd572fa7fb1333090dc9fbc6b44507e31dc25c1b81f7a8c147d6"}, 942 | {file = "fastrlock-0.5-cp37-cp37m-win32.whl", hash = "sha256:7bafd414b93b016b6501c5a921e30e0aec0f504b080dfeaa37c90a620b2d30a8"}, 943 | {file = "fastrlock-0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:0980c4b158eed24cd28723231bb834a5d22723dd3f11e1303830ce5641713cbb"}, 944 | {file = "fastrlock-0.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:4e25339c13a424efe6af8db199f0b7af62f3dfb526177a4340b2ddf8a62f9520"}, 945 | {file = "fastrlock-0.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d643eb3c9df29332d92d93bba803e964ba0c543a5bbb746670e9d94bc43d949a"}, 946 | {file = "fastrlock-0.5-cp38-cp38-win32.whl", hash = "sha256:8a6bfc42e381610abd67eb283c34485ec9cd23ddb436b68cece618ba7ad0c526"}, 947 | {file = "fastrlock-0.5-cp38-cp38-win_amd64.whl", hash = "sha256:39b1e97011dcef282018524823799756deb14b11b8b3f472fe14464693d9e3d3"}, 948 | {file = "fastrlock-0.5.tar.gz", hash = "sha256:9ae1a31f6e069b5f0f28ba63c594d0c952065de0a375f7b491d21ebaccc5166f"}, 949 | ] 950 | filelock = [ 951 | {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, 952 | {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, 953 | ] 954 | flake8 = [ 955 | {file = "flake8-3.8.4-py2.py3-none-any.whl", hash = "sha256:749dbbd6bfd0cf1318af27bf97a14e28e5ff548ef8e5b1566ccfb25a11e7c839"}, 956 | {file = "flake8-3.8.4.tar.gz", hash = "sha256:aadae8761ec651813c24be05c6f7b4680857ef6afaae4651a4eccaef97ce6c3b"}, 957 | ] 958 | flask = [ 959 | {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, 960 | {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, 961 | ] 962 | gensim = [ 963 | {file = "gensim-3.8.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:61eed1d6b5fbe6dda0586ea447ebc2dc7890a7f70c2ed953d5abc3fe3cfb94bb"}, 964 | {file = "gensim-3.8.3-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3af62709369331c85552fd26caa21504baa64accc426dc094172f5c688750013"}, 965 | {file = "gensim-3.8.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8ff471921b3b10ffb3ae6cbb598dd9c07d9dc030dee5aa167e7682b549c42f87"}, 966 | {file = "gensim-3.8.3-cp27-cp27m-win32.whl", hash = "sha256:440700e29b494bc2e1d52e14b69a821f46ab09ecf85cf36c8988f18e1d6c7a8b"}, 967 | {file = "gensim-3.8.3-cp27-cp27m-win_amd64.whl", hash = "sha256:f8ea67bf8c47ee55cb1b32c97fa1474b7d6d22959dd8097c019a5d9c9df34f5f"}, 968 | {file = "gensim-3.8.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7a90549dfc8ee3822fcad6da957de07d927e4e90ef42b3699543dee35ab2da13"}, 969 | {file = "gensim-3.8.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7629b33cf35f672efdd5269381f7e301958ee2638f27dfc63b80c5bfeaa827d3"}, 970 | {file = "gensim-3.8.3-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:6711b6d3a0007530ee7de7adc30a4c48a1d26ec6312ac50e1d1e0a1d54f9de5b"}, 971 | {file = "gensim-3.8.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:ef2ddeceff482aee17c1e185f63bf027c8de8f595fdd9fd2d2503de96008f3b7"}, 972 | {file = "gensim-3.8.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:41dcf6ecdc9acc657157967c791b8cbaba90ee6391f64efd28339b72f5e0c327"}, 973 | {file = "gensim-3.8.3-cp35-cp35m-win32.whl", hash = "sha256:685a7657278161628821c8f873c5d7d2ffc0c28866648e39f76b450e4c7d5390"}, 974 | {file = "gensim-3.8.3-cp35-cp35m-win_amd64.whl", hash = "sha256:b61a7c841a752c84b685674aa0d610289faad38795b325176481abe19b487e98"}, 975 | {file = "gensim-3.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a61179df454a0d4b06a111c4ede0536f61c8121b4c0d0d02d23560a2fd4b3aff"}, 976 | {file = "gensim-3.8.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:cc387d0d8bddbf3609ab95b3453296e4c9ff92c35e9799a17d86b1571d77a5fc"}, 977 | {file = "gensim-3.8.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:b36e6330471061cfd78aad751e24c6b4f56d575697af0fbab42655128927d296"}, 978 | {file = "gensim-3.8.3-cp36-cp36m-win32.whl", hash = "sha256:1e3d66c2eec494376fc599701d9c2868549aed6e93e47177e39217f0188e2d88"}, 979 | {file = "gensim-3.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:91fa62d61b21f1878f140b10520f9de4a26a52672fbe407edfc7e09ca2eff235"}, 980 | {file = "gensim-3.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:637fc5969f3cef4b7c8fd3e78e31ef09565c5566d5ceabf076b4170eb6444a80"}, 981 | {file = "gensim-3.8.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:22f45fd239cacd0e3715ac447a2c8a5eea02e730ec1f701c55b359e9298e63a8"}, 982 | {file = "gensim-3.8.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d79370f78e9013b9d1e867c85ecc678d46a7ae0f01a8ca29e8f4291e5373b170"}, 983 | {file = "gensim-3.8.3-cp37-cp37m-win32.whl", hash = "sha256:9c214b341f5304b906c79844e2787c13b46505df9dc70afca79a9a7dc0894478"}, 984 | {file = "gensim-3.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:fe98277a7b3b4987b40c928056bbaae1d0715022cf27bba89d05cd0d4fe51a84"}, 985 | {file = "gensim-3.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a47903d104469a7a8b6f22ad5ef74681b19c4f4b71ff2c2893271b53161a43e4"}, 986 | {file = "gensim-3.8.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:05bfc02e102a34c9c795095b688b1b4aaa2529c624821368c9c3ea6a16536f77"}, 987 | {file = "gensim-3.8.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a8807ebf324dd11e1298a91a92d6e57c7bdabb91d0d5240bf1efa0c0eacd86f0"}, 988 | {file = "gensim-3.8.3-cp38-cp38-win32.whl", hash = "sha256:90115d12ee545c21cc75521ef1bb3dd66aae8a378e9c2eb029c9f22df173c125"}, 989 | {file = "gensim-3.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:4e34cf2e50f3eab3e303da46089ea4972567bf216e28f7535ada155770784ac8"}, 990 | {file = "gensim-3.8.3.tar.gz", hash = "sha256:786adb0571f75114e9c5f7a31dd2e6eb39a9791f22c8757621545e2ded3ea367"}, 991 | ] 992 | gevent = [ 993 | {file = "gevent-20.12.1-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:0f9fa230c5878704b9e286ad5038bac3b70d293bf10e9efa8b2ae1d7d80e7e08"}, 994 | {file = "gevent-20.12.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:f020bfb34d57caa10029111be776524c378a4aac8417bc6fb1154b05e00fc220"}, 995 | {file = "gevent-20.12.1-cp27-cp27m-win32.whl", hash = "sha256:e233ae153b586b61e492806d4cd1be2217de7441922c02053b67de14800bce96"}, 996 | {file = "gevent-20.12.1-cp27-cp27m-win_amd64.whl", hash = "sha256:2d05f38a5ef1ebb7ceb692897674b11ba603914524765b989c65c020c7b08360"}, 997 | {file = "gevent-20.12.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:ffa1be13963db6aa55c50d2fd4a656c82f53a03a47e37aaa69e79a488123538d"}, 998 | {file = "gevent-20.12.1-cp35-cp35m-win32.whl", hash = "sha256:caec00914e8f21b2c77a29bbc2ef3abfeadf7515656e5451dfb14c2064733998"}, 999 | {file = "gevent-20.12.1-cp35-cp35m-win_amd64.whl", hash = "sha256:19bd3fe60dec45fe6420b7772496950215f1b36701905876ba1644b6b2064163"}, 1000 | {file = "gevent-20.12.1-cp36-cp36m-win32.whl", hash = "sha256:9d001fc899db6e140110ae7484e58cd74b0dfa5cee021a0347f00bb441ac78bd"}, 1001 | {file = "gevent-20.12.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b57586ad3fedf13d351d2559b70d6fe593c50400315d52bb3c072285da60fa37"}, 1002 | {file = "gevent-20.12.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:69ddc1767a02f68e71d5e0d3215aa4d28872187715627f71ff0eadd7b7a5e7f4"}, 1003 | {file = "gevent-20.12.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:89c583744f91052ae987356660f5ed0b8fc59a1230b051d6ccc10d37a155fe01"}, 1004 | {file = "gevent-20.12.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f3faf1834464f1b0731aa6346cd9f41029fa9e208d6ecbce4a736c19562c86aa"}, 1005 | {file = "gevent-20.12.1-cp37-cp37m-win32.whl", hash = "sha256:4baecba0fd614e14dc1f3f8c35616cb248cdb893de576150ed1fc7fc66b8ba3d"}, 1006 | {file = "gevent-20.12.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4b0a5626c4e534d184cdf00d66f06de3885beafaaa5f7b98d47186ea175629a1"}, 1007 | {file = "gevent-20.12.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:81e38ed46e21e0b00b930efce1a1ff46c7722ad83d84052f71a757f23cbed1c0"}, 1008 | {file = "gevent-20.12.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:895c76a89907d9d37fdfaf5321cb0fff0cba396f003bedb4f5fc13836da6f250"}, 1009 | {file = "gevent-20.12.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c3706a620e167c4bd007f16f113928324c4e07a7bae11d6d18d65f82abcd7a58"}, 1010 | {file = "gevent-20.12.1-cp38-cp38-win32.whl", hash = "sha256:ba244028225ff8d3a58f344fcd16ab05b0e3642b34d81f51f7fa3c70761f6c34"}, 1011 | {file = "gevent-20.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c570a2e3100f758a5c2f9b993ecf870ee784390e44e1a292c361d6b32fb3ad4c"}, 1012 | {file = "gevent-20.12.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:f857adbe1bf41e620d86173a53100f4ec328eba3089069a4815b3d9f4229dee8"}, 1013 | {file = "gevent-20.12.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bf946a99e364ebcc95b82c794d5d1a67f13115adbefab7b9e12791f13184cfd5"}, 1014 | {file = "gevent-20.12.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:60799fd7dcbb622f8435eb12436d48a8d27f8e7b3d23631e32ccc04ddd2097c2"}, 1015 | {file = "gevent-20.12.1-pp27-pypy_73-win32.whl", hash = "sha256:7a808c63f065a303bbbe87c5c0754e06abb1e23e18752f418dce1eb3189cb43d"}, 1016 | {file = "gevent-20.12.1.tar.gz", hash = "sha256:99b68765767bb3e2244a66b012883899a6f17c23b6dc1cd80b793df341e15f08"}, 1017 | ] 1018 | greenlet = [ 1019 | {file = "greenlet-0.4.17-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:75e4c27188f28149b74e7685809f9227410fd15432a4438fc48627f518577fa5"}, 1020 | {file = "greenlet-0.4.17-cp27-cp27m-win32.whl", hash = "sha256:3af587e9813f9bd8be9212722321a5e7be23b2bc37e6323a90e592ab0c2ef117"}, 1021 | {file = "greenlet-0.4.17-cp27-cp27m-win_amd64.whl", hash = "sha256:ccd62f09f90b2730150d82f2f2ffc34d73c6ce7eac234aed04d15dc8a3023994"}, 1022 | {file = "greenlet-0.4.17-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:13037e2d7ab2145300676852fa069235512fdeba4ed1e3bb4b0677a04223c525"}, 1023 | {file = "greenlet-0.4.17-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:e495096e3e2e8f7192afb6aaeba19babc4fb2bdf543d7b7fed59e00c1df7f170"}, 1024 | {file = "greenlet-0.4.17-cp35-cp35m-win32.whl", hash = "sha256:124a3ae41215f71dc91d1a3d45cbf2f84e46b543e5d60b99ecc20e24b4c8f272"}, 1025 | {file = "greenlet-0.4.17-cp35-cp35m-win_amd64.whl", hash = "sha256:5494e3baeacc371d988345fbf8aa4bd15555b3077c40afcf1994776bb6d77eaf"}, 1026 | {file = "greenlet-0.4.17-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bee111161420f341a346731279dd976be161b465c1286f82cc0779baf7b729e8"}, 1027 | {file = "greenlet-0.4.17-cp36-cp36m-win32.whl", hash = "sha256:ac85db59aa43d78547f95fc7b6fd2913e02b9e9b09e2490dfb7bbdf47b2a4914"}, 1028 | {file = "greenlet-0.4.17-cp36-cp36m-win_amd64.whl", hash = "sha256:4481002118b2f1588fa3d821936ffdc03db80ef21186b62b90c18db4ba5e743b"}, 1029 | {file = "greenlet-0.4.17-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:be7a79988b8fdc5bbbeaed69e79cfb373da9759242f1565668be4fb7f3f37552"}, 1030 | {file = "greenlet-0.4.17-cp37-cp37m-win32.whl", hash = "sha256:97f2b01ab622a4aa4b3724a3e1fba66f47f054c434fbaa551833fa2b41e3db51"}, 1031 | {file = "greenlet-0.4.17-cp37-cp37m-win_amd64.whl", hash = "sha256:d3436110ca66fe3981031cc6aff8cc7a40d8411d173dde73ddaa5b8445385e2d"}, 1032 | {file = "greenlet-0.4.17-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a34023b9eabb3525ee059f3bf33a417d2e437f7f17e341d334987d4091ae6072"}, 1033 | {file = "greenlet-0.4.17-cp38-cp38-win32.whl", hash = "sha256:e66a824f44892bc4ec66c58601a413419cafa9cec895e63d8da889c8a1a4fa4a"}, 1034 | {file = "greenlet-0.4.17-cp38-cp38-win_amd64.whl", hash = "sha256:47825c3a109f0331b1e54c1173d4e57fa000aa6c96756b62852bfa1af91cd652"}, 1035 | {file = "greenlet-0.4.17-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1023d7b43ca11264ab7052cb09f5635d4afdb43df55e0854498fc63070a0b206"}, 1036 | {file = "greenlet-0.4.17.tar.gz", hash = "sha256:41d8835c69a78de718e466dd0e6bfd4b46125f21a67c3ff6d76d8d8059868d6b"}, 1037 | ] 1038 | idna = [ 1039 | {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, 1040 | {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, 1041 | ] 1042 | importlib-metadata = [ 1043 | {file = "importlib_metadata-3.3.0-py3-none-any.whl", hash = "sha256:bf792d480abbd5eda85794e4afb09dd538393f7d6e6ffef6e9f03d2014cf9450"}, 1044 | {file = "importlib_metadata-3.3.0.tar.gz", hash = "sha256:5c5a2720817414a6c41f0a49993908068243ae02c1635a228126519b509c8aed"}, 1045 | ] 1046 | iniconfig = [ 1047 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 1048 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 1049 | ] 1050 | itsdangerous = [ 1051 | {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, 1052 | {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, 1053 | ] 1054 | jinja2 = [ 1055 | {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, 1056 | {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, 1057 | ] 1058 | joblib = [ 1059 | {file = "joblib-1.0.0-py3-none-any.whl", hash = "sha256:75ead23f13484a2a414874779d69ade40d4fa1abe62b222a23cd50d4bc822f6f"}, 1060 | {file = "joblib-1.0.0.tar.gz", hash = "sha256:7ad866067ac1fdec27d51c8678ea760601b70e32ff1881d4dc8e1171f2b64b24"}, 1061 | ] 1062 | mako = [ 1063 | {file = "Mako-1.1.3-py2.py3-none-any.whl", hash = "sha256:93729a258e4ff0747c876bd9e20df1b9758028946e976324ccd2d68245c7b6a9"}, 1064 | {file = "Mako-1.1.3.tar.gz", hash = "sha256:8195c8c1400ceb53496064314c6736719c6f25e7479cd24c77be3d9361cddc27"}, 1065 | ] 1066 | markupsafe = [ 1067 | {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, 1068 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, 1069 | {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, 1070 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, 1071 | {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, 1072 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, 1073 | {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, 1074 | {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, 1075 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, 1076 | {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, 1077 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, 1078 | {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, 1079 | {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, 1080 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, 1081 | {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, 1082 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, 1083 | {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, 1084 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, 1085 | {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, 1086 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, 1087 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, 1088 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, 1089 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, 1090 | {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, 1091 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, 1092 | {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, 1093 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, 1094 | {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, 1095 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, 1096 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, 1097 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, 1098 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, 1099 | {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, 1100 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, 1101 | {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, 1102 | {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, 1103 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, 1104 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, 1105 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, 1106 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, 1107 | {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, 1108 | {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, 1109 | {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, 1110 | {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, 1111 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, 1112 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, 1113 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, 1114 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, 1115 | {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, 1116 | {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, 1117 | {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, 1118 | {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, 1119 | ] 1120 | mccabe = [ 1121 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 1122 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 1123 | ] 1124 | msgpack = [ 1125 | {file = "msgpack-1.0.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:b6d9e2dae081aa35c44af9c4298de4ee72991305503442a5c74656d82b581fe9"}, 1126 | {file = "msgpack-1.0.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:a99b144475230982aee16b3d249170f1cccebf27fb0a08e9f603b69637a62192"}, 1127 | {file = "msgpack-1.0.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1026dcc10537d27dd2d26c327e552f05ce148977e9d7b9f1718748281b38c841"}, 1128 | {file = "msgpack-1.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:fe07bc6735d08e492a327f496b7850e98cb4d112c56df69b0c844dbebcbb47f6"}, 1129 | {file = "msgpack-1.0.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:9ea52fff0473f9f3000987f313310208c879493491ef3ccf66268eff8d5a0326"}, 1130 | {file = "msgpack-1.0.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:26a1759f1a88df5f1d0b393eb582ec022326994e311ba9c5818adc5374736439"}, 1131 | {file = "msgpack-1.0.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:497d2c12426adcd27ab83144057a705efb6acc7e85957a51d43cdcf7f258900f"}, 1132 | {file = "msgpack-1.0.2-cp36-cp36m-win32.whl", hash = "sha256:e89ec55871ed5473a041c0495b7b4e6099f6263438e0bd04ccd8418f92d5d7f2"}, 1133 | {file = "msgpack-1.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a4355d2193106c7aa77c98fc955252a737d8550320ecdb2e9ac701e15e2943bc"}, 1134 | {file = "msgpack-1.0.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:d6c64601af8f3893d17ec233237030e3110f11b8a962cb66720bf70c0141aa54"}, 1135 | {file = "msgpack-1.0.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f484cd2dca68502de3704f056fa9b318c94b1539ed17a4c784266df5d6978c87"}, 1136 | {file = "msgpack-1.0.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:f3e6aaf217ac1c7ce1563cf52a2f4f5d5b1f64e8729d794165db71da57257f0c"}, 1137 | {file = "msgpack-1.0.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:8521e5be9e3b93d4d5e07cb80b7e32353264d143c1f072309e1863174c6aadb1"}, 1138 | {file = "msgpack-1.0.2-cp37-cp37m-win32.whl", hash = "sha256:31c17bbf2ae5e29e48d794c693b7ca7a0c73bd4280976d408c53df421e838d2a"}, 1139 | {file = "msgpack-1.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8ffb24a3b7518e843cd83538cf859e026d24ec41ac5721c18ed0c55101f9775b"}, 1140 | {file = "msgpack-1.0.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:b28c0876cce1466d7c2195d7658cf50e4730667196e2f1355c4209444717ee06"}, 1141 | {file = "msgpack-1.0.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:87869ba567fe371c4555d2e11e4948778ab6b59d6cc9d8460d543e4cfbbddd1c"}, 1142 | {file = "msgpack-1.0.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b55f7db883530b74c857e50e149126b91bb75d35c08b28db12dcb0346f15e46e"}, 1143 | {file = "msgpack-1.0.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:ac25f3e0513f6673e8b405c3a80500eb7be1cf8f57584be524c4fa78fe8e0c83"}, 1144 | {file = "msgpack-1.0.2-cp38-cp38-win32.whl", hash = "sha256:0cb94ee48675a45d3b86e61d13c1e6f1696f0183f0715544976356ff86f741d9"}, 1145 | {file = "msgpack-1.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:e36a812ef4705a291cdb4a2fd352f013134f26c6ff63477f20235138d1d21009"}, 1146 | {file = "msgpack-1.0.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:2a5866bdc88d77f6e1370f82f2371c9bc6fc92fe898fa2dec0c5d4f5435a2694"}, 1147 | {file = "msgpack-1.0.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:92be4b12de4806d3c36810b0fe2aeedd8d493db39e2eb90742b9c09299eb5759"}, 1148 | {file = "msgpack-1.0.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:de6bd7990a2c2dabe926b7e62a92886ccbf809425c347ae7de277067f97c2887"}, 1149 | {file = "msgpack-1.0.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:5a9ee2540c78659a1dd0b110f73773533ee3108d4e1219b5a15a8d635b7aca0e"}, 1150 | {file = "msgpack-1.0.2-cp39-cp39-win32.whl", hash = "sha256:c747c0cc08bd6d72a586310bda6ea72eeb28e7505990f342552315b229a19b33"}, 1151 | {file = "msgpack-1.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:d8167b84af26654c1124857d71650404336f4eb5cc06900667a493fc619ddd9f"}, 1152 | {file = "msgpack-1.0.2.tar.gz", hash = "sha256:fae04496f5bc150eefad4e9571d1a76c55d021325dcd484ce45065ebbdd00984"}, 1153 | ] 1154 | mypy = [ 1155 | {file = "mypy-0.790-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669"}, 1156 | {file = "mypy-0.790-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802"}, 1157 | {file = "mypy-0.790-cp35-cp35m-win_amd64.whl", hash = "sha256:e86bdace26c5fe9cf8cb735e7cedfe7850ad92b327ac5d797c656717d2ca66de"}, 1158 | {file = "mypy-0.790-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e97e9c13d67fbe524be17e4d8025d51a7dca38f90de2e462243ab8ed8a9178d1"}, 1159 | {file = "mypy-0.790-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0d34d6b122597d48a36d6c59e35341f410d4abfa771d96d04ae2c468dd201abc"}, 1160 | {file = "mypy-0.790-cp36-cp36m-win_amd64.whl", hash = "sha256:72060bf64f290fb629bd4a67c707a66fd88ca26e413a91384b18db3876e57ed7"}, 1161 | {file = "mypy-0.790-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:eea260feb1830a627fb526d22fbb426b750d9f5a47b624e8d5e7e004359b219c"}, 1162 | {file = "mypy-0.790-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c614194e01c85bb2e551c421397e49afb2872c88b5830e3554f0519f9fb1c178"}, 1163 | {file = "mypy-0.790-cp37-cp37m-win_amd64.whl", hash = "sha256:0a0d102247c16ce93c97066443d11e2d36e6cc2a32d8ccc1f705268970479324"}, 1164 | {file = "mypy-0.790-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf4e7bf7f1214826cf7333627cb2547c0db7e3078723227820d0a2490f117a01"}, 1165 | {file = "mypy-0.790-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:af4e9ff1834e565f1baa74ccf7ae2564ae38c8df2a85b057af1dbbc958eb6666"}, 1166 | {file = "mypy-0.790-cp38-cp38-win_amd64.whl", hash = "sha256:da56dedcd7cd502ccd3c5dddc656cb36113dd793ad466e894574125945653cea"}, 1167 | {file = "mypy-0.790-py3-none-any.whl", hash = "sha256:2842d4fbd1b12ab422346376aad03ff5d0805b706102e475e962370f874a5122"}, 1168 | {file = "mypy-0.790.tar.gz", hash = "sha256:2b21ba45ad9ef2e2eb88ce4aeadd0112d0f5026418324176fd494a6824b74975"}, 1169 | ] 1170 | mypy-extensions = [ 1171 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 1172 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 1173 | ] 1174 | numpy = [ 1175 | {file = "numpy-1.19.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e9b30d4bd69498fc0c3fe9db5f62fffbb06b8eb9321f92cc970f2969be5e3949"}, 1176 | {file = "numpy-1.19.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:fedbd128668ead37f33917820b704784aff695e0019309ad446a6d0b065b57e4"}, 1177 | {file = "numpy-1.19.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8ece138c3a16db8c1ad38f52eb32be6086cc72f403150a79336eb2045723a1ad"}, 1178 | {file = "numpy-1.19.4-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:64324f64f90a9e4ef732be0928be853eee378fd6a01be21a0a8469c4f2682c83"}, 1179 | {file = "numpy-1.19.4-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ad6f2ff5b1989a4899bf89800a671d71b1612e5ff40866d1f4d8bcf48d4e5764"}, 1180 | {file = "numpy-1.19.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d6c7bb82883680e168b55b49c70af29b84b84abb161cbac2800e8fcb6f2109b6"}, 1181 | {file = "numpy-1.19.4-cp36-cp36m-win32.whl", hash = "sha256:13d166f77d6dc02c0a73c1101dd87fdf01339febec1030bd810dcd53fff3b0f1"}, 1182 | {file = "numpy-1.19.4-cp36-cp36m-win_amd64.whl", hash = "sha256:448ebb1b3bf64c0267d6b09a7cba26b5ae61b6d2dbabff7c91b660c7eccf2bdb"}, 1183 | {file = "numpy-1.19.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:27d3f3b9e3406579a8af3a9f262f5339005dd25e0ecf3cf1559ff8a49ed5cbf2"}, 1184 | {file = "numpy-1.19.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:16c1b388cc31a9baa06d91a19366fb99ddbe1c7b205293ed072211ee5bac1ed2"}, 1185 | {file = "numpy-1.19.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e5b6ed0f0b42317050c88022349d994fe72bfe35f5908617512cd8c8ef9da2a9"}, 1186 | {file = "numpy-1.19.4-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:18bed2bcb39e3f758296584337966e68d2d5ba6aab7e038688ad53c8f889f757"}, 1187 | {file = "numpy-1.19.4-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:fe45becb4c2f72a0907c1d0246ea6449fe7a9e2293bb0e11c4e9a32bb0930a15"}, 1188 | {file = "numpy-1.19.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:6d7593a705d662be5bfe24111af14763016765f43cb6923ed86223f965f52387"}, 1189 | {file = "numpy-1.19.4-cp37-cp37m-win32.whl", hash = "sha256:6ae6c680f3ebf1cf7ad1d7748868b39d9f900836df774c453c11c5440bc15b36"}, 1190 | {file = "numpy-1.19.4-cp37-cp37m-win_amd64.whl", hash = "sha256:9eeb7d1d04b117ac0d38719915ae169aa6b61fca227b0b7d198d43728f0c879c"}, 1191 | {file = "numpy-1.19.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cb1017eec5257e9ac6209ac172058c430e834d5d2bc21961dceeb79d111e5909"}, 1192 | {file = "numpy-1.19.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:edb01671b3caae1ca00881686003d16c2209e07b7ef8b7639f1867852b948f7c"}, 1193 | {file = "numpy-1.19.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:f29454410db6ef8126c83bd3c968d143304633d45dc57b51252afbd79d700893"}, 1194 | {file = "numpy-1.19.4-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:ec149b90019852266fec2341ce1db513b843e496d5a8e8cdb5ced1923a92faab"}, 1195 | {file = "numpy-1.19.4-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1aeef46a13e51931c0b1cf8ae1168b4a55ecd282e6688fdb0a948cc5a1d5afb9"}, 1196 | {file = "numpy-1.19.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:08308c38e44cc926bdfce99498b21eec1f848d24c302519e64203a8da99a97db"}, 1197 | {file = "numpy-1.19.4-cp38-cp38-win32.whl", hash = "sha256:5734bdc0342aba9dfc6f04920988140fb41234db42381cf7ccba64169f9fe7ac"}, 1198 | {file = "numpy-1.19.4-cp38-cp38-win_amd64.whl", hash = "sha256:09c12096d843b90eafd01ea1b3307e78ddd47a55855ad402b157b6c4862197ce"}, 1199 | {file = "numpy-1.19.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e452dc66e08a4ce642a961f134814258a082832c78c90351b75c41ad16f79f63"}, 1200 | {file = "numpy-1.19.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:a5d897c14513590a85774180be713f692df6fa8ecf6483e561a6d47309566f37"}, 1201 | {file = "numpy-1.19.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:a09f98011236a419ee3f49cedc9ef27d7a1651df07810ae430a6b06576e0b414"}, 1202 | {file = "numpy-1.19.4-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:50e86c076611212ca62e5a59f518edafe0c0730f7d9195fec718da1a5c2bb1fc"}, 1203 | {file = "numpy-1.19.4-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f0d3929fe88ee1c155129ecd82f981b8856c5d97bcb0d5f23e9b4242e79d1de3"}, 1204 | {file = "numpy-1.19.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c42c4b73121caf0ed6cd795512c9c09c52a7287b04d105d112068c1736d7c753"}, 1205 | {file = "numpy-1.19.4-cp39-cp39-win32.whl", hash = "sha256:8cac8790a6b1ddf88640a9267ee67b1aee7a57dfa2d2dd33999d080bc8ee3a0f"}, 1206 | {file = "numpy-1.19.4-cp39-cp39-win_amd64.whl", hash = "sha256:4377e10b874e653fe96985c05feed2225c912e328c8a26541f7fc600fb9c637b"}, 1207 | {file = "numpy-1.19.4-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:2a2740aa9733d2e5b2dfb33639d98a64c3b0f24765fed86b0fd2aec07f6a0a08"}, 1208 | {file = "numpy-1.19.4.zip", hash = "sha256:141ec3a3300ab89c7f2b0775289954d193cc8edb621ea05f99db9cb181530512"}, 1209 | ] 1210 | packaging = [ 1211 | {file = "packaging-20.8-py2.py3-none-any.whl", hash = "sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858"}, 1212 | {file = "packaging-20.8.tar.gz", hash = "sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"}, 1213 | ] 1214 | pathspec = [ 1215 | {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, 1216 | {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, 1217 | ] 1218 | pluggy = [ 1219 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 1220 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 1221 | ] 1222 | protobuf = [ 1223 | {file = "protobuf-3.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:629b03fd3caae7f815b0c66b41273f6b1900a579e2ccb41ef4493a4f5fb84f3a"}, 1224 | {file = "protobuf-3.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5b7a637212cc9b2bcf85dd828b1178d19efdf74dbfe1ddf8cd1b8e01fdaaa7f5"}, 1225 | {file = "protobuf-3.14.0-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:43b554b9e73a07ba84ed6cf25db0ff88b1e06be610b37656e292e3cbb5437472"}, 1226 | {file = "protobuf-3.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5e9806a43232a1fa0c9cf5da8dc06f6910d53e4390be1fa06f06454d888a9142"}, 1227 | {file = "protobuf-3.14.0-cp35-cp35m-win32.whl", hash = "sha256:1c51fda1bbc9634246e7be6016d860be01747354ed7015ebe38acf4452f470d2"}, 1228 | {file = "protobuf-3.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:4b74301b30513b1a7494d3055d95c714b560fbb630d8fb9956b6f27992c9f980"}, 1229 | {file = "protobuf-3.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:86a75477addde4918e9a1904e5c6af8d7b691f2a3f65587d73b16100fbe4c3b2"}, 1230 | {file = "protobuf-3.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecc33531a213eee22ad60e0e2aaea6c8ba0021f0cce35dbf0ab03dee6e2a23a1"}, 1231 | {file = "protobuf-3.14.0-cp36-cp36m-win32.whl", hash = "sha256:72230ed56f026dd664c21d73c5db73ebba50d924d7ba6b7c0d81a121e390406e"}, 1232 | {file = "protobuf-3.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:0fc96785262042e4863b3f3b5c429d4636f10d90061e1840fce1baaf59b1a836"}, 1233 | {file = "protobuf-3.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4e75105c9dfe13719b7293f75bd53033108f4ba03d44e71db0ec2a0e8401eafd"}, 1234 | {file = "protobuf-3.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2a7e2fe101a7ace75e9327b9c946d247749e564a267b0515cf41dfe450b69bac"}, 1235 | {file = "protobuf-3.14.0-cp37-cp37m-win32.whl", hash = "sha256:b0d5d35faeb07e22a1ddf8dce620860c8fe145426c02d1a0ae2688c6e8ede36d"}, 1236 | {file = "protobuf-3.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8971c421dbd7aad930c9bd2694122f332350b6ccb5202a8b7b06f3f1a5c41ed5"}, 1237 | {file = "protobuf-3.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9616f0b65a30851e62f1713336c931fcd32c057202b7ff2cfbfca0fc7d5e3043"}, 1238 | {file = "protobuf-3.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:22bcd2e284b3b1d969c12e84dc9b9a71701ec82d8ce975fdda19712e1cfd4e00"}, 1239 | {file = "protobuf-3.14.0-py2.py3-none-any.whl", hash = "sha256:0e247612fadda953047f53301a7b0407cb0c3cb4ae25a6fde661597a04039b3c"}, 1240 | {file = "protobuf-3.14.0.tar.gz", hash = "sha256:1d63eb389347293d8915fb47bee0951c7b5dab522a4a60118b9a18f33e21f8ce"}, 1241 | ] 1242 | py = [ 1243 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, 1244 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, 1245 | ] 1246 | pycodestyle = [ 1247 | {file = "pycodestyle-2.6.0-py2.py3-none-any.whl", hash = "sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367"}, 1248 | {file = "pycodestyle-2.6.0.tar.gz", hash = "sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"}, 1249 | ] 1250 | pycparser = [ 1251 | {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, 1252 | {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, 1253 | ] 1254 | pyflakes = [ 1255 | {file = "pyflakes-2.2.0-py2.py3-none-any.whl", hash = "sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92"}, 1256 | {file = "pyflakes-2.2.0.tar.gz", hash = "sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"}, 1257 | ] 1258 | pyparsing = [ 1259 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 1260 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 1261 | ] 1262 | pytest = [ 1263 | {file = "pytest-6.2.1-py3-none-any.whl", hash = "sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8"}, 1264 | {file = "pytest-6.2.1.tar.gz", hash = "sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"}, 1265 | ] 1266 | python-dateutil = [ 1267 | {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, 1268 | {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, 1269 | ] 1270 | python-editor = [ 1271 | {file = "python-editor-1.0.4.tar.gz", hash = "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b"}, 1272 | {file = "python_editor-1.0.4-py2-none-any.whl", hash = "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8"}, 1273 | {file = "python_editor-1.0.4-py2.7.egg", hash = "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522"}, 1274 | {file = "python_editor-1.0.4-py3-none-any.whl", hash = "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d"}, 1275 | {file = "python_editor-1.0.4-py3.5.egg", hash = "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77"}, 1276 | ] 1277 | pyyaml = [ 1278 | {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, 1279 | {file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"}, 1280 | {file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"}, 1281 | {file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"}, 1282 | {file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"}, 1283 | {file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"}, 1284 | {file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"}, 1285 | {file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"}, 1286 | {file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"}, 1287 | {file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"}, 1288 | {file = "PyYAML-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ad9c67312c84def58f3c04504727ca879cb0013b2517c85a9a253f0cb6380c0a"}, 1289 | {file = "PyYAML-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:6034f55dab5fea9e53f436aa68fa3ace2634918e8b5994d82f3621c04ff5ed2e"}, 1290 | {file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"}, 1291 | ] 1292 | regex = [ 1293 | {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, 1294 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, 1295 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, 1296 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, 1297 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, 1298 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, 1299 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, 1300 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, 1301 | {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, 1302 | {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, 1303 | {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, 1304 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, 1305 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, 1306 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, 1307 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, 1308 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, 1309 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, 1310 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, 1311 | {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, 1312 | {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, 1313 | {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, 1314 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, 1315 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, 1316 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, 1317 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, 1318 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, 1319 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, 1320 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, 1321 | {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, 1322 | {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, 1323 | {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, 1324 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, 1325 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, 1326 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, 1327 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, 1328 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, 1329 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, 1330 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, 1331 | {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, 1332 | {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, 1333 | {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, 1334 | ] 1335 | requests = [ 1336 | {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, 1337 | {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, 1338 | ] 1339 | scikit-learn = [ 1340 | {file = "scikit-learn-0.24.0.tar.gz", hash = "sha256:076369634ee72b5a5941440661e2f306ff4ac30903802dc52031c7e9199ac640"}, 1341 | {file = "scikit_learn-0.24.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:890d7d588f65acb0c4f6c083347c9076916bda5e6bd8400f06244b1afc1009af"}, 1342 | {file = "scikit_learn-0.24.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:e534f5f3796db6781c87e9835dcd51b7854c8c5a379c9210b93605965c1941fd"}, 1343 | {file = "scikit_learn-0.24.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:d7fe05fcb44eadd6d6c874c768f085f5de1239db3a3b7be4d3d23d12e4120589"}, 1344 | {file = "scikit_learn-0.24.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:7f654befc5ad413690cc58f3f34a3e906caf825195ce0fda00a8e9565e1403e6"}, 1345 | {file = "scikit_learn-0.24.0-cp36-cp36m-win32.whl", hash = "sha256:afeb06dc69847927634e58579b9cdc72e1390b79497336b2324b1b173f33bd47"}, 1346 | {file = "scikit_learn-0.24.0-cp36-cp36m-win_amd64.whl", hash = "sha256:26f66b3726b54dfb76ea51c5d9c2431ed17ebc066cb4527662b9e851a3e7ba61"}, 1347 | {file = "scikit_learn-0.24.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c08b27cb78ee8d2dc781a7affed09859441f5b624f9f92da59ac0791c8774dfc"}, 1348 | {file = "scikit_learn-0.24.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:905d8934d1e27a686698864a5863ff2c0e13a2ae1adb78a8a848aacc8a49927d"}, 1349 | {file = "scikit_learn-0.24.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d819d625832fb2969911a243e009cfa135cb8ef1e150866e417d6e9d75290087"}, 1350 | {file = "scikit_learn-0.24.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:18f7131e62265bf2691ed1d0303c640313894ccfe4278427478c6b2f45094b53"}, 1351 | {file = "scikit_learn-0.24.0-cp37-cp37m-win32.whl", hash = "sha256:b0d13fd56d26cf3de0314a4fd48037108c638fe126d813f5c1222bb0f08b6a76"}, 1352 | {file = "scikit_learn-0.24.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c912247e42114f389858ae05d63f4359d4e667ea72aaabee191aee9ad3f9774a"}, 1353 | {file = "scikit_learn-0.24.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:758619e49cd7c17282e6cc60d5cc73c02c072b47c9a10010bb3bb47e0d976e50"}, 1354 | {file = "scikit_learn-0.24.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:66f27bf21202a850bcd7b6303916e4907f6e22ec59a14974ede4955aed5c7ed0"}, 1355 | {file = "scikit_learn-0.24.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:5e6e3c042cea83f2e20a45e563b8eabc1f8f72446251fe23ebefdf111a173a33"}, 1356 | {file = "scikit_learn-0.24.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2a5348585aa793bc8cc5a72f8e9067c9380834b0aadbd55f924843b071f13282"}, 1357 | {file = "scikit_learn-0.24.0-cp38-cp38-win32.whl", hash = "sha256:743b6edd98c98991be46c08e6b21df3861d5ae915f91d59f988384d93f7263e7"}, 1358 | {file = "scikit_learn-0.24.0-cp38-cp38-win_amd64.whl", hash = "sha256:2951f87d35e72f007701c6e028aa230f6df6212a3194677c0c950486066a454d"}, 1359 | {file = "scikit_learn-0.24.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:44e452ea8491225c5783d49577aad0f36202dfd52aec7f82c0fdfe5fbd5f7400"}, 1360 | {file = "scikit_learn-0.24.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:800aaf63f8838c00e85db2267dd226f89858594843fd03932a9eda95746d2c40"}, 1361 | {file = "scikit_learn-0.24.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:3eeff086f7329521d27249a082ea3c48c085cedb110db5f65968ab55c3ba2e09"}, 1362 | {file = "scikit_learn-0.24.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:4395e91b3548005f4a645018435b5a94f8cce232b5b70753020e606c6a750656"}, 1363 | {file = "scikit_learn-0.24.0-cp39-cp39-win32.whl", hash = "sha256:80ca024154b84b6ac4cfc86930ba13fdc348a209753bf2c16129db6f9eb8a80b"}, 1364 | {file = "scikit_learn-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:490436b44b3a1957cb625e871764b0aa330b34cc416aea4abc6c38ca63d0d682"}, 1365 | ] 1366 | scipy = [ 1367 | {file = "scipy-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4f12d13ffbc16e988fa40809cbbd7a8b45bc05ff6ea0ba8e3e41f6f4db3a9e47"}, 1368 | {file = "scipy-1.5.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a254b98dbcc744c723a838c03b74a8a34c0558c9ac5c86d5561703362231107d"}, 1369 | {file = "scipy-1.5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:368c0f69f93186309e1b4beb8e26d51dd6f5010b79264c0f1e9ca00cd92ea8c9"}, 1370 | {file = "scipy-1.5.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4598cf03136067000855d6b44d7a1f4f46994164bcd450fb2c3d481afc25dd06"}, 1371 | {file = "scipy-1.5.4-cp36-cp36m-win32.whl", hash = "sha256:e98d49a5717369d8241d6cf33ecb0ca72deee392414118198a8e5b4c35c56340"}, 1372 | {file = "scipy-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:65923bc3809524e46fb7eb4d6346552cbb6a1ffc41be748535aa502a2e3d3389"}, 1373 | {file = "scipy-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9ad4fcddcbf5dc67619379782e6aeef41218a79e17979aaed01ed099876c0e62"}, 1374 | {file = "scipy-1.5.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f87b39f4d69cf7d7529d7b1098cb712033b17ea7714aed831b95628f483fd012"}, 1375 | {file = "scipy-1.5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:25b241034215247481f53355e05f9e25462682b13bd9191359075682adcd9554"}, 1376 | {file = "scipy-1.5.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:fa789583fc94a7689b45834453fec095245c7e69c58561dc159b5d5277057e4c"}, 1377 | {file = "scipy-1.5.4-cp37-cp37m-win32.whl", hash = "sha256:d6d25c41a009e3c6b7e757338948d0076ee1dd1770d1c09ec131f11946883c54"}, 1378 | {file = "scipy-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:2c872de0c69ed20fb1a9b9cf6f77298b04a26f0b8720a5457be08be254366c6e"}, 1379 | {file = "scipy-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e360cb2299028d0b0d0f65a5c5e51fc16a335f1603aa2357c25766c8dab56938"}, 1380 | {file = "scipy-1.5.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3397c129b479846d7eaa18f999369a24322d008fac0782e7828fa567358c36ce"}, 1381 | {file = "scipy-1.5.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:168c45c0c32e23f613db7c9e4e780bc61982d71dcd406ead746c7c7c2f2004ce"}, 1382 | {file = "scipy-1.5.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:213bc59191da2f479984ad4ec39406bf949a99aba70e9237b916ce7547b6ef42"}, 1383 | {file = "scipy-1.5.4-cp38-cp38-win32.whl", hash = "sha256:634568a3018bc16a83cda28d4f7aed0d803dd5618facb36e977e53b2df868443"}, 1384 | {file = "scipy-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:b03c4338d6d3d299e8ca494194c0ae4f611548da59e3c038813f1a43976cb437"}, 1385 | {file = "scipy-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3d5db5d815370c28d938cf9b0809dade4acf7aba57eaf7ef733bfedc9b2474c4"}, 1386 | {file = "scipy-1.5.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b0ceb23560f46dd236a8ad4378fc40bad1783e997604ba845e131d6c680963e"}, 1387 | {file = "scipy-1.5.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:ed572470af2438b526ea574ff8f05e7f39b44ac37f712105e57fc4d53a6fb660"}, 1388 | {file = "scipy-1.5.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8c8d6ca19c8497344b810b0b0344f8375af5f6bb9c98bd42e33f747417ab3f57"}, 1389 | {file = "scipy-1.5.4-cp39-cp39-win32.whl", hash = "sha256:d84cadd7d7998433334c99fa55bcba0d8b4aeff0edb123b2a1dfcface538e474"}, 1390 | {file = "scipy-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:cc1f78ebc982cd0602c9a7615d878396bec94908db67d4ecddca864d049112f2"}, 1391 | {file = "scipy-1.5.4.tar.gz", hash = "sha256:4a453d5e5689de62e5d38edf40af3f17560bfd63c9c5bd228c18c1f99afa155b"}, 1392 | ] 1393 | seqeval = [ 1394 | {file = "seqeval-1.2.2.tar.gz", hash = "sha256:f28e97c3ab96d6fcd32b648f6438ff2e09cfba87f05939da9b3970713ec56e6f"}, 1395 | ] 1396 | six = [ 1397 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 1398 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 1399 | ] 1400 | smart-open = [ 1401 | {file = "smart_open-4.0.1.tar.gz", hash = "sha256:49396d86de8e0d609ec40422c59f837dd944dcdf727feed6f2ff8cbdc0e3bc8e"}, 1402 | ] 1403 | sqlalchemy = [ 1404 | {file = "SQLAlchemy-1.3.22-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:61628715931f4962e0cdb2a7c87ff39eea320d2aa96bd471a3c293d146f90394"}, 1405 | {file = "SQLAlchemy-1.3.22-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:81d8d099a49f83111cce55ec03cc87eef45eec0d90f9842b4fc674f860b857b0"}, 1406 | {file = "SQLAlchemy-1.3.22-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:d055ff750fcab69ca4e57b656d9c6ad33682e9b8d564f2fbe667ab95c63591b0"}, 1407 | {file = "SQLAlchemy-1.3.22-cp27-cp27m-win32.whl", hash = "sha256:9bf572e4f5aa23f88dd902f10bb103cb5979022a38eec684bfa6d61851173fec"}, 1408 | {file = "SQLAlchemy-1.3.22-cp27-cp27m-win_amd64.whl", hash = "sha256:7d4b8de6bb0bc736161cb0bbd95366b11b3eb24dd6b814a143d8375e75af9990"}, 1409 | {file = "SQLAlchemy-1.3.22-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4a84c7c7658dd22a33dab2e2aa2d17c18cb004a42388246f2e87cb4085ef2811"}, 1410 | {file = "SQLAlchemy-1.3.22-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:f1e88b30da8163215eab643962ae9d9252e47b4ea53404f2c4f10f24e70ddc62"}, 1411 | {file = "SQLAlchemy-1.3.22-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f115150cc4361dd46153302a640c7fa1804ac207f9cc356228248e351a8b4676"}, 1412 | {file = "SQLAlchemy-1.3.22-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:6aaa13ee40c4552d5f3a59f543f0db6e31712cc4009ec7385407be4627259d41"}, 1413 | {file = "SQLAlchemy-1.3.22-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:3ab5b44a07b8c562c6dcb7433c6a6c6e03266d19d64f87b3333eda34e3b9936b"}, 1414 | {file = "SQLAlchemy-1.3.22-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:426ece890153ccc52cc5151a1a0ed540a5a7825414139bb4c95a868d8da54a52"}, 1415 | {file = "SQLAlchemy-1.3.22-cp35-cp35m-win32.whl", hash = "sha256:bd4b1af45fd322dcd1fb2a9195b4f93f570d1a5902a842e3e6051385fac88f9c"}, 1416 | {file = "SQLAlchemy-1.3.22-cp35-cp35m-win_amd64.whl", hash = "sha256:62285607a5264d1f91590abd874d6a498e229d5840669bd7d9f654cfaa599bd0"}, 1417 | {file = "SQLAlchemy-1.3.22-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:314f5042c0b047438e19401d5f29757a511cfc2f0c40d28047ca0e4c95eabb5b"}, 1418 | {file = "SQLAlchemy-1.3.22-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:62fb881ba51dbacba9af9b779211cf9acff3442d4f2993142015b22b3cd1f92a"}, 1419 | {file = "SQLAlchemy-1.3.22-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:bde677047305fe76c7ee3e4492b545e0018918e44141cc154fe39e124e433991"}, 1420 | {file = "SQLAlchemy-1.3.22-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:0c6406a78a714a540d980a680b86654feadb81c8d0eecb59f3d6c554a4c69f19"}, 1421 | {file = "SQLAlchemy-1.3.22-cp36-cp36m-win32.whl", hash = "sha256:95bde07d19c146d608bccb9b16e144ec8f139bcfe7fd72331858698a71c9b4f5"}, 1422 | {file = "SQLAlchemy-1.3.22-cp36-cp36m-win_amd64.whl", hash = "sha256:888d5b4b5aeed0d3449de93ea80173653e939e916cc95fe8527079e50235c1d2"}, 1423 | {file = "SQLAlchemy-1.3.22-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:d53f59744b01f1440a1b0973ed2c3a7de204135c593299ee997828aad5191693"}, 1424 | {file = "SQLAlchemy-1.3.22-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:70121f0ae48b25ef3e56e477b88cd0b0af0e1f3a53b5554071aa6a93ef378a03"}, 1425 | {file = "SQLAlchemy-1.3.22-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:54da615e5b92c339e339fe8536cce99fe823b6ed505d4ea344852aefa1c205fb"}, 1426 | {file = "SQLAlchemy-1.3.22-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:68428818cf80c60dc04aa0f38da20ad39b28aba4d4d199f949e7d6e04444ea86"}, 1427 | {file = "SQLAlchemy-1.3.22-cp37-cp37m-win32.whl", hash = "sha256:17610d573e698bf395afbbff946544fbce7c5f4ee77b5bcb1f821b36345fae7a"}, 1428 | {file = "SQLAlchemy-1.3.22-cp37-cp37m-win_amd64.whl", hash = "sha256:216ba5b4299c95ed179b58f298bda885a476b16288ab7243e89f29f6aeced7e0"}, 1429 | {file = "SQLAlchemy-1.3.22-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:0c72b90988be749e04eff0342dcc98c18a14461eb4b2ad59d611b57b31120f90"}, 1430 | {file = "SQLAlchemy-1.3.22-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:491fe48adc07d13e020a8b07ef82eefc227003a046809c121bea81d3dbf1832d"}, 1431 | {file = "SQLAlchemy-1.3.22-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f8191fef303025879e6c3548ecd8a95aafc0728c764ab72ec51a0bdf0c91a341"}, 1432 | {file = "SQLAlchemy-1.3.22-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:108580808803c7732f34798eb4a329d45b04c562ed83ee90f09f6a184a42b766"}, 1433 | {file = "SQLAlchemy-1.3.22-cp38-cp38-win32.whl", hash = "sha256:bab5a1e15b9466a25c96cda19139f3beb3e669794373b9ce28c4cf158c6e841d"}, 1434 | {file = "SQLAlchemy-1.3.22-cp38-cp38-win_amd64.whl", hash = "sha256:318b5b727e00662e5fc4b4cd2bf58a5116d7c1b4dd56ffaa7d68f43458a8d1ed"}, 1435 | {file = "SQLAlchemy-1.3.22-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:1418f5e71d6081aa1095a1d6b567a562d2761996710bdce9b6e6ba20a03d0864"}, 1436 | {file = "SQLAlchemy-1.3.22-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:5a7f224cdb7233182cec2a45d4c633951268d6a9bcedac37abbf79dd07012aea"}, 1437 | {file = "SQLAlchemy-1.3.22-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:715b34578cc740b743361f7c3e5f584b04b0f1344f45afc4e87fbac4802eb0a0"}, 1438 | {file = "SQLAlchemy-1.3.22-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:2ff132a379838b1abf83c065be54cef32b47c987aedd06b82fc76476c85225eb"}, 1439 | {file = "SQLAlchemy-1.3.22-cp39-cp39-win32.whl", hash = "sha256:c389d7cc2b821853fb018c85457da3e7941db64f4387720a329bc7ff06a27963"}, 1440 | {file = "SQLAlchemy-1.3.22-cp39-cp39-win_amd64.whl", hash = "sha256:04f995fcbf54e46cddeb4f75ce9dfc17075d6ae04ac23b2bacb44b3bc6f6bf11"}, 1441 | {file = "SQLAlchemy-1.3.22.tar.gz", hash = "sha256:758fc8c4d6c0336e617f9f6919f9daea3ab6bb9b07005eda9a1a682e24a6cacc"}, 1442 | ] 1443 | structlog = [ 1444 | {file = "structlog-20.1.0-py2.py3-none-any.whl", hash = "sha256:8a672be150547a93d90a7d74229a29e765be05bd156a35cdcc527ebf68e9af92"}, 1445 | {file = "structlog-20.1.0.tar.gz", hash = "sha256:7a48375db6274ed1d0ae6123c486472aa1d0890b08d314d2b016f3aa7f35990b"}, 1446 | ] 1447 | threadpoolctl = [ 1448 | {file = "threadpoolctl-2.1.0-py3-none-any.whl", hash = "sha256:38b74ca20ff3bb42caca8b00055111d74159ee95c4370882bbff2b93d24da725"}, 1449 | {file = "threadpoolctl-2.1.0.tar.gz", hash = "sha256:ddc57c96a38beb63db45d6c159b5ab07b6bced12c45a1f07b2b92f272aebfa6b"}, 1450 | ] 1451 | toml = [ 1452 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 1453 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1454 | ] 1455 | typed-ast = [ 1456 | {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, 1457 | {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, 1458 | {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, 1459 | {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, 1460 | {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, 1461 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, 1462 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, 1463 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:fcf135e17cc74dbfbc05894ebca928ffeb23d9790b3167a674921db19082401f"}, 1464 | {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, 1465 | {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, 1466 | {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, 1467 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, 1468 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, 1469 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:f208eb7aff048f6bea9586e61af041ddf7f9ade7caed625742af423f6bae3298"}, 1470 | {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, 1471 | {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, 1472 | {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, 1473 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, 1474 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, 1475 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:7e4c9d7658aaa1fc80018593abdf8598bf91325af6af5cce4ce7c73bc45ea53d"}, 1476 | {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, 1477 | {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, 1478 | {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, 1479 | {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:92c325624e304ebf0e025d1224b77dd4e6393f18aab8d829b5b7e04afe9b7a2c"}, 1480 | {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:d648b8e3bf2fe648745c8ffcee3db3ff903d0817a01a12dd6a6ea7a8f4889072"}, 1481 | {file = "typed_ast-1.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fac11badff8313e23717f3dada86a15389d0708275bddf766cca67a84ead3e91"}, 1482 | {file = "typed_ast-1.4.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0d8110d78a5736e16e26213114a38ca35cb15b6515d535413b090bd50951556d"}, 1483 | {file = "typed_ast-1.4.1-cp39-cp39-win32.whl", hash = "sha256:b52ccf7cfe4ce2a1064b18594381bccf4179c2ecf7f513134ec2f993dd4ab395"}, 1484 | {file = "typed_ast-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:3742b32cf1c6ef124d57f95be609c473d7ec4c14d0090e5a5e05a15269fb4d0c"}, 1485 | {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, 1486 | ] 1487 | typing-extensions = [ 1488 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 1489 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 1490 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 1491 | ] 1492 | urllib3 = [ 1493 | {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, 1494 | {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, 1495 | ] 1496 | werkzeug = [ 1497 | {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, 1498 | {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, 1499 | ] 1500 | zipp = [ 1501 | {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, 1502 | {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, 1503 | ] 1504 | "zope.event" = [ 1505 | {file = "zope.event-4.5.0-py2.py3-none-any.whl", hash = "sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42"}, 1506 | {file = "zope.event-4.5.0.tar.gz", hash = "sha256:5e76517f5b9b119acf37ca8819781db6c16ea433f7e2062c4afc2b6fbedb1330"}, 1507 | ] 1508 | "zope.interface" = [ 1509 | {file = "zope.interface-5.2.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:518950fe6a5d56f94ba125107895f938a4f34f704c658986eae8255edb41163b"}, 1510 | {file = "zope.interface-5.2.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:6278c080d4afffc9016e14325f8734456831124e8c12caa754fd544435c08386"}, 1511 | {file = "zope.interface-5.2.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:538298e4e113ccb8b41658d5a4b605bebe75e46a30ceca22a5a289cf02c80bec"}, 1512 | {file = "zope.interface-5.2.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:778d0ec38bbd288b150a3ae363c8ffd88d2207a756842495e9bffd8a8afbc89a"}, 1513 | {file = "zope.interface-5.2.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:64ea6c221aeee4796860405e1aedec63424cda4202a7ad27a5066876db5b0fd2"}, 1514 | {file = "zope.interface-5.2.0-cp27-cp27m-win32.whl", hash = "sha256:92dc0fb79675882d0b6138be4bf0cec7ea7c7eede60aaca78303d8e8dbdaa523"}, 1515 | {file = "zope.interface-5.2.0-cp27-cp27m-win_amd64.whl", hash = "sha256:844fad925ac5c2ad4faaceb3b2520ad016b5280105c6e16e79838cf951903a7b"}, 1516 | {file = "zope.interface-5.2.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:588384d70a0f19b47409cfdb10e0c27c20e4293b74fc891df3d8eb47782b8b3e"}, 1517 | {file = "zope.interface-5.2.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:07d61722dd7d85547b7c6b0f5486b4338001fab349f2ac5cabc0b7182eb3425d"}, 1518 | {file = "zope.interface-5.2.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:495b63fd0302f282ee6c1e6ea0f1c12cb3d1a49c8292d27287f01845ff252a96"}, 1519 | {file = "zope.interface-5.2.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:299bde0ab9e5c4a92f01a152b7fbabb460f31343f1416f9b7b983167ab1e33bc"}, 1520 | {file = "zope.interface-5.2.0-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:32546af61a9a9b141ca38d971aa6eb9800450fa6620ce6323cc30eec447861f3"}, 1521 | {file = "zope.interface-5.2.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2ab88d8f228f803fcb8cb7d222c579d13dab2d3622c51e8cf321280da01102a7"}, 1522 | {file = "zope.interface-5.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:cbd0f2cbd8689861209cd89141371d3a22a11613304d1f0736492590aa0ab332"}, 1523 | {file = "zope.interface-5.2.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:21e49123f375703cf824214939d39df0af62c47d122d955b2a8d9153ea08cfd5"}, 1524 | {file = "zope.interface-5.2.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:eccac3d9aadc68e994b6d228cb0c8919fc47a5350d85a1b4d3d81d1e98baf40c"}, 1525 | {file = "zope.interface-5.2.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:42b278ac0989d6f5cf58d7e0828ea6b5951464e3cf2ff229dd09a96cb6ba0c86"}, 1526 | {file = "zope.interface-5.2.0-cp35-cp35m-win32.whl", hash = "sha256:83b4aa5344cce005a9cff5d0321b2e318e871cc1dfc793b66c32dd4f59e9770d"}, 1527 | {file = "zope.interface-5.2.0-cp35-cp35m-win_amd64.whl", hash = "sha256:4df9afd17bd5477e9f8c8b6bb8507e18dd0f8b4efe73bb99729ff203279e9e3b"}, 1528 | {file = "zope.interface-5.2.0-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:1743bcfe45af8846b775086471c28258f4c6e9ee8ef37484de4495f15a98b549"}, 1529 | {file = "zope.interface-5.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:aedc6c672b351afe6dfe17ff83ee5e7eb6ed44718f879a9328a68bdb20b57e11"}, 1530 | {file = "zope.interface-5.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4af87cdc0d4b14e600e6d3d09793dce3b7171348a094ba818e2a68ae7ee67546"}, 1531 | {file = "zope.interface-5.2.0-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:b7a00ecb1434f8183395fac5366a21ee73d14900082ca37cf74993cf46baa56c"}, 1532 | {file = "zope.interface-5.2.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:8ceb3667dd13b8133f2e4d637b5b00f240f066448e2aa89a41f4c2d78a26ce50"}, 1533 | {file = "zope.interface-5.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:efef581c8ba4d990770875e1a2218e856849d32ada2680e53aebc5d154a17e20"}, 1534 | {file = "zope.interface-5.2.0-cp36-cp36m-win32.whl", hash = "sha256:e4bc372b953bf6cec65a8d48482ba574f6e051621d157cf224227dbb55486b1e"}, 1535 | {file = "zope.interface-5.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3cc94c69f6bd48ed86e8e24f358cb75095c8129827df1298518ab860115269a4"}, 1536 | {file = "zope.interface-5.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ba32f4a91c1cb7314c429b03afbf87b1fff4fb1c8db32260e7310104bd77f0c7"}, 1537 | {file = "zope.interface-5.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1b5f6c8fff4ed32aa2dd43e84061bc8346f32d3ba6ad6e58f088fe109608f102"}, 1538 | {file = "zope.interface-5.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:efd550b3da28195746bb43bd1d815058181a7ca6d9d6aa89dd37f5eefe2cacb7"}, 1539 | {file = "zope.interface-5.2.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:aab9f1e34d810feb00bf841993552b8fcc6ae71d473c505381627143d0018a6a"}, 1540 | {file = "zope.interface-5.2.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:55465121e72e208a7b69b53de791402affe6165083b2ea71b892728bd19ba9ae"}, 1541 | {file = "zope.interface-5.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:32b40a4c46d199827d79c86bb8cb88b1bbb764f127876f2cb6f3a47f63dbada3"}, 1542 | {file = "zope.interface-5.2.0-cp37-cp37m-win32.whl", hash = "sha256:abb61afd84f23099ac6099d804cdba9bd3b902aaaded3ffff47e490b0a495520"}, 1543 | {file = "zope.interface-5.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:21f579134a47083ffb5ddd1307f0405c91aa8b61ad4be6fd5af0171474fe0c45"}, 1544 | {file = "zope.interface-5.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4c48ddb63e2b20fba4c6a2bf81b4d49e99b6d4587fb67a6cd33a2c1f003af3e3"}, 1545 | {file = "zope.interface-5.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2dcab01c660983ba5e5a612e0c935141ccbee67d2e2e14b833e01c2354bd8034"}, 1546 | {file = "zope.interface-5.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:150e8bcb7253a34a4535aeea3de36c0bb3b1a6a47a183a95d65a194b3e07f232"}, 1547 | {file = "zope.interface-5.2.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:681dbb33e2b40262b33fd383bae63c36d33fd79fa1a8e4092945430744ffd34a"}, 1548 | {file = "zope.interface-5.2.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:2ced4c35061eea623bc84c7711eedce8ecc3c2c51cd9c6afa6290df3bae9e104"}, 1549 | {file = "zope.interface-5.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f37d45fab14ffef9d33a0dc3bc59ce0c5313e2253323312d47739192da94f5fd"}, 1550 | {file = "zope.interface-5.2.0-cp38-cp38-win32.whl", hash = "sha256:9789bd945e9f5bd026ed3f5b453d640befb8b1fc33a779c1fe8d3eb21fe3fb4a"}, 1551 | {file = "zope.interface-5.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0a990dcc97806e5980bbb54b2e46b9cde9e48932d8e6984daf71ef1745516123"}, 1552 | {file = "zope.interface-5.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4b94df9f2fdde7b9314321bab8448e6ad5a23b80542dcab53e329527d4099dcb"}, 1553 | {file = "zope.interface-5.2.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6936aa9da390402d646a32a6a38d5409c2d2afb2950f045a7d02ab25a4e7d08d"}, 1554 | {file = "zope.interface-5.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:adf9ee115ae8ff8b6da4b854b4152f253b390ba64407a22d75456fe07dcbda65"}, 1555 | {file = "zope.interface-5.2.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:f44906f70205d456d503105023041f1e63aece7623b31c390a0103db4de17537"}, 1556 | {file = "zope.interface-5.2.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f057897711a630a0b7a6a03f1acf379b6ba25d37dc5dc217a97191984ba7f2fc"}, 1557 | {file = "zope.interface-5.2.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:05a97ba92c1c7c26f25c9f671aa1ef85ffead6cdad13770e5b689cf983adc7e1"}, 1558 | {file = "zope.interface-5.2.0-cp39-cp39-win32.whl", hash = "sha256:27c267dc38a0f0079e96a2945ee65786d38ef111e413c702fbaaacbab6361d00"}, 1559 | {file = "zope.interface-5.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:a2b6d6eb693bc2fc6c484f2e5d93bd0b0da803fa77bf974f160533e555e4d095"}, 1560 | {file = "zope.interface-5.2.0.tar.gz", hash = "sha256:8251f06a77985a2729a8bdbefbae79ee78567dddc3acbd499b87e705ca59fe24"}, 1561 | ] 1562 | -------------------------------------------------------------------------------- /pyner/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himkt/pyner/91371db03bbe7d621f76281c9a26affac00e8034/pyner/__init__.py -------------------------------------------------------------------------------- /pyner/named_entity/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himkt/pyner/91371db03bbe7d621f76281c9a26affac00e8034/pyner/named_entity/__init__.py -------------------------------------------------------------------------------- /pyner/named_entity/corpus.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | BOS = 0 # begin of step 4 | EOS = 1 # end of step 5 | XXX = 2 # other 6 | 7 | 8 | def split_tag(tag: str): 9 | """ 10 | Split tag into state and named entity category. 11 | 12 | Parameters 13 | --- 14 | tag (str) 15 | NE tag (e.g. B-PER) 16 | """ 17 | if tag in ["O", "-X-"]: 18 | state, label = "O", None 19 | else: 20 | state, label = tag.split("-") 21 | return state, label 22 | 23 | 24 | def iob2bio(tags): 25 | processed_tags = [] # should be bio format 26 | prev_state = None 27 | prev_label = None 28 | 29 | for t, tag in enumerate(tags): 30 | state, label = split_tag(tag) 31 | 32 | # case1. I-ORG I-ORG 33 | # ^^^^^ 34 | if t == 0 and state == "I": 35 | new_state = "B" 36 | 37 | # case2. I-ORG I-PERSON 38 | # ^^^^^^^^ 39 | elif state == "I" and prev_label != label: 40 | new_state = "B" 41 | 42 | # case3. O I-ORG 43 | # ^^^^^ 44 | elif state == "I" and prev_state == "O": 45 | new_state = "B" 46 | 47 | # case4. I-ORG I-ORG 48 | # ^^^^^ 49 | elif state == "I" and prev_label == label: 50 | new_state = "I" 51 | 52 | else: 53 | new_state = state 54 | 55 | if label is None: 56 | new_tag = "O" 57 | 58 | else: 59 | new_tag = f"{new_state}-{label}" 60 | 61 | processed_tags.append(new_tag) 62 | prev_state = state 63 | prev_label = label 64 | 65 | return processed_tags 66 | 67 | 68 | def bio2bioes(tags): 69 | # BIO -> BIOES: it only needs to check next 70 | processed_tags = [] # should be bio format 71 | last_index = len(tags) - 1 72 | 73 | for t, tag in enumerate(tags): 74 | state, label = split_tag(tag) 75 | 76 | if t == last_index: 77 | next_state, _ = "O", None 78 | 79 | else: 80 | next_state, _ = split_tag(tags[t + 1]) 81 | 82 | # case1. B-ORG O or B-ORG B-ORG 83 | # ^^^^^ ^^^^^ 84 | if state == "B" and next_state in ["B", "O"]: 85 | new_state = "S" 86 | 87 | # case2. I-ORG O or I-ORG B-PER 88 | # ^^^^^ ^^^^^ 89 | elif state == "I" and next_state in ["B", "O"]: 90 | new_state = "E" 91 | 92 | # case3. I-ORG I-ORG 93 | # ^^^^^ 94 | elif state == "I" and next_state == "I": 95 | new_state = "I" 96 | 97 | else: 98 | new_state = state 99 | 100 | if label is None: 101 | new_tag = "O" 102 | 103 | else: 104 | new_tag = f"{new_state}-{label}" 105 | 106 | processed_tags.append(new_tag) 107 | return processed_tags 108 | 109 | 110 | def get_word_format_func(in_format, out_format): 111 | format_func_list = [] 112 | if in_format == "bio" and out_format == "bioes": 113 | format_func_list.append(bio2bioes) 114 | 115 | if in_format == "iob" and out_format == "bio": 116 | format_func_list.append(iob2bio) 117 | 118 | if in_format == "iob" and out_format == "bioes": 119 | format_func_list.append(iob2bio) 120 | format_func_list.append(bio2bioes) 121 | 122 | return format_func_list 123 | 124 | 125 | def apply_transform(elems, format_func_list): 126 | for func in format_func_list: 127 | elems = func(elems) 128 | return elems 129 | 130 | 131 | def enum(word_sentences, tag_sentences): 132 | """ 133 | enumerate words, chars and tags for 134 | constructing vocabularies. 135 | """ 136 | 137 | words = sorted(list(set(sum(word_sentences, [])))) 138 | chars = sorted(list(set(sum([list(word) for word in words], [])))) 139 | tags = sorted(list(set(sum(tag_sentences, [])))) 140 | 141 | return words, chars, tags 142 | 143 | 144 | def write_sentences(mode, sentences, output_path): 145 | target = output_path / f"{mode}.txt" 146 | with open(target, "w") as file: 147 | for sentence in sentences: 148 | for token in zip(*sentence): 149 | print("\t".join(token), file=file) 150 | print("", file=file) 151 | 152 | 153 | def write_vocab(prefix, elems, output_path): 154 | target = output_path / f"vocab.{prefix}.txt" 155 | with open(target, "w") as file: 156 | print("\n".join(elems), file=file) 157 | 158 | 159 | class CorpusParser: 160 | def __init__(self, convert_rule, delimiter): 161 | self.delimiter = delimiter 162 | if convert_rule: 163 | in_format, out_format = convert_rule.split("2") 164 | self.format_func_list = get_word_format_func(in_format, out_format) 165 | 166 | else: 167 | self.format_func_list = [] 168 | 169 | def parse_file(self, file, word_idx=2, tag_idx=-1): 170 | annotated_file = open(file, encoding="utf-8") 171 | annotated_body = annotated_file.read() 172 | document = annotated_body.split("\n") 173 | return self._parse(document, word_idx, tag_idx) 174 | 175 | def _parse(self, document, word_idx, tag_idx): 176 | word_sentences = [] 177 | tag_sentences = [] 178 | 179 | status = BOS 180 | 181 | word_sentence = [] 182 | tag_sentence = [] 183 | 184 | for line in document: 185 | line = line.rstrip(" ").rstrip("\n") 186 | elems = re.split(self.delimiter, line) 187 | 188 | if line.startswith("-DOCSTART-"): 189 | continue 190 | 191 | if line == "": 192 | # EOR (end of recipe) 193 | status = EOS 194 | 195 | elif line.startswith("ID="): 196 | # BOR (begin of recipe) 197 | status = BOS 198 | 199 | elif len(elems) >= 4: 200 | status, word, tag = XXX, elems[word_idx], elems[tag_idx] 201 | 202 | if tag.endswith("-B") or tag.endswith("-I"): 203 | # suffix-style -> prefix-style (CoNLL is prefix-style) 204 | tag = "-".join(tag.split("-")[::-1]) 205 | 206 | else: 207 | raise Exception 208 | 209 | if status == XXX: 210 | word_sentence.append(word) 211 | tag_sentence.append(tag) 212 | 213 | elif status == EOS: 214 | if not word_sentence: 215 | continue 216 | 217 | word_sentences.append(word_sentence) 218 | 219 | arguments = (tag_sentence, self.format_func_list) 220 | tag_sentence = apply_transform(*arguments) 221 | tag_sentences.append(tag_sentence) 222 | 223 | # clean sentence for new input 224 | word_sentence = [] 225 | tag_sentence = [] 226 | 227 | elif status == BOS: 228 | assert not word_sentence 229 | assert not tag_sentence 230 | 231 | return word_sentences, tag_sentences 232 | -------------------------------------------------------------------------------- /pyner/named_entity/dataset.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import chainer.dataset as D 4 | import numpy as np 5 | from chainer.backends import cuda 6 | import os.path 7 | 8 | logger = logging.getLogger(__name__) 9 | 10 | 11 | def update_instances(train_datas, params, mode): 12 | if mode == "train": 13 | train_size = params.get("train_size", 1.0) 14 | rate = 100 * train_size 15 | else: 16 | train_size = 1.0 17 | rate = 100 18 | 19 | if train_size <= 0 or 1 <= train_size: 20 | assert Exception("train_size must be in (0, 1]") 21 | 22 | n_instances = int(train_size * len(train_datas)) 23 | logger.debug(f"Use {n_instances} example for {mode} ({rate:.2f}%)") 24 | 25 | result = [[] for _ in train_datas[0][0]] 26 | for instance in train_datas[:n_instances]: 27 | for index, sentence in enumerate(list(zip(*instance))): 28 | result[index].append(sentence) 29 | return result 30 | 31 | 32 | def converter(batch, device=-1): 33 | wss, css, tss = list(zip(*batch)) 34 | 35 | xp = cuda.cupy if device >= 0 else np 36 | wss = [xp.asarray(ws, dtype=xp.int32) for ws in wss] 37 | css = [[xp.asarray(c, dtype=xp.int32) for c in cs] for cs in css] 38 | 39 | if tss[0] is not None: 40 | tss = [xp.asarray(ts, dtype=xp.int32) for ts in tss] 41 | else: 42 | tss = None 43 | 44 | return (wss, css), tss 45 | 46 | 47 | class DatasetTransformer: 48 | def __init__(self, vocab): 49 | self.word2idx = vocab.dictionaries["word2idx"] 50 | self.char2idx = vocab.dictionaries["char2idx"] 51 | self.tag2idx = vocab.dictionaries["tag2idx"] 52 | 53 | self.idx2word = {idx: word for word, idx in self.word2idx.items()} 54 | self.idx2tag = {idx: tag for tag, idx in self.tag2idx.items()} 55 | self.replace_zero = vocab.replace_zero 56 | 57 | @staticmethod 58 | def _to_id(elems, dictionary): 59 | unk_id = dictionary.get("") 60 | es = [dictionary.get(e, unk_id) for e in elems] 61 | return es 62 | 63 | def transform(self, word_sentence, tag_sentence): 64 | wordid_sentence = self._to_id(word_sentence, self.word2idx) 65 | charid_sentence = [ 66 | self._to_id(cs, self.char2idx) for cs in word_sentence 67 | ] # NOQA 68 | 69 | if tag_sentence is not None: 70 | tagid_sentence = self._to_id(tag_sentence, self.tag2idx) 71 | else: 72 | tagid_sentence = None 73 | 74 | return wordid_sentence, charid_sentence, tagid_sentence 75 | 76 | def itransform(self, wordid_sentences, tagid_sentences): 77 | """ 78 | convert wordids and tagids into words and tags 79 | if you want to itransform iterator's output: 80 | > (words, _), tags = batch 81 | > itransform(words, tags) 82 | """ 83 | sentences = zip(wordid_sentences, tagid_sentences) 84 | return [self._itransform(ws, ts) for ws, ts in sentences] 85 | 86 | def _itransform(self, wordid_sentence, tagid_sentence): 87 | wordid_sentence = cuda.to_cpu(wordid_sentence) 88 | tagid_sentence = cuda.to_cpu(tagid_sentence) 89 | word_sentence = [self.idx2word[wid] for wid in wordid_sentence] 90 | tag_sentence = [self.idx2tag[tid] for tid in tagid_sentence] 91 | 92 | return word_sentence, tag_sentence 93 | 94 | 95 | class SequenceLabelingDataset(D.DatasetMixin): 96 | def __init__(self, vocab, params, mode, transform, return_original_sentence=False): 97 | data_path = os.path.join(params["data_dir"], f"{mode}.txt") 98 | datas = vocab.load_word_sentences(data_path) 99 | word_sentences, tag_sentences = update_instances(datas, params, mode) 100 | self.word_sentences = word_sentences 101 | self.tag_sentences = tag_sentences 102 | 103 | self.return_original_sentence = return_original_sentence 104 | self.num_sentences = len(word_sentences) 105 | self.transform = transform 106 | 107 | def __len__(self): 108 | return self.num_sentences 109 | 110 | def get_example(self, i): 111 | word_line = self.word_sentences[i] 112 | tag_line = self.tag_sentences[i] 113 | 114 | ret = self.transform(word_line, tag_line) 115 | if self.return_original_sentence: 116 | return ret, word_line 117 | else: 118 | return ret 119 | -------------------------------------------------------------------------------- /pyner/named_entity/evaluator.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | from chainer import function, reporter 4 | from chainer.training.extensions import Evaluator 5 | from seqeval import metrics 6 | 7 | 8 | class NamedEntityEvaluator(Evaluator): 9 | def __init__(self, iterator, target, transform_func, converter, device=-1): 10 | super(NamedEntityEvaluator, self).__init__(iterator, target, converter, device) 11 | 12 | self.transform_func = transform_func 13 | self.device = device 14 | 15 | def evaluate(self): 16 | iterator = self.get_iterator("main") 17 | target = self.get_target("main") 18 | 19 | if hasattr(iterator, "reset"): 20 | iterator.reset() 21 | it = iterator 22 | else: 23 | it = copy.copy(iterator) 24 | 25 | summary = reporter.DictSummary() 26 | 27 | for batch in it: 28 | observation = {} 29 | with reporter.report_scope(observation): 30 | with function.no_backprop_mode(): 31 | in_arrays, t_arrays = self.converter(batch, self.device) 32 | 33 | p_arrays = target.predict(in_arrays) 34 | _, t_tag_sentences = list( 35 | zip(*self.transform_func(in_arrays[0], t_arrays)) 36 | ) 37 | _, p_tag_sentences = list( 38 | zip(*self.transform_func(in_arrays[0], p_arrays)) 39 | ) 40 | 41 | fscore = metrics.f1_score(t_tag_sentences, p_tag_sentences) 42 | 43 | reporter.report({"loss": target(in_arrays, t_arrays)}, target) 44 | reporter.report({"fscore": fscore}, target) 45 | 46 | summary.add(observation) 47 | 48 | return summary.compute_mean() 49 | -------------------------------------------------------------------------------- /pyner/named_entity/inference.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | from typing import Optional 4 | 5 | import click 6 | import chainer 7 | import os.path 8 | 9 | from chainer.backends import cuda 10 | from pyner.named_entity.dataset import DatasetTransformer, converter 11 | from pyner.named_entity.recognizer import BiLSTM_CRF 12 | from pyner.util.deterministic import set_seed 13 | from pyner.util.iterator import create_iterator 14 | from pyner.util.metric import select_snapshot 15 | from pyner.util.vocab import Vocabulary 16 | 17 | 18 | @click.command() 19 | @click.argument("model_dir") 20 | @click.option("--epoch", type=int) 21 | @click.option("--device", type=int, default=-1) 22 | @click.option("--metric", type=str, default="validation/main/fscore") 23 | def run_inference(model_dir: str, epoch: Optional[int], device: str, metric: str): 24 | chainer.config.train = False 25 | 26 | if device >= 0: 27 | cuda.get_device(device).use() 28 | 29 | set_seed() 30 | 31 | configs = json.load(open(os.path.join(model_dir, "args"))) 32 | snapshot_file, prediction_path = select_snapshot(epoch, metric, model_dir) 33 | logger.debug(f"creat prediction into {prediction_path}") 34 | 35 | vocab = Vocabulary.prepare(configs) 36 | num_word_vocab = configs["num_word_vocab"] 37 | num_char_vocab = configs["num_char_vocab"] 38 | num_tag_vocab = configs["num_tag_vocab"] 39 | 40 | model = BiLSTM_CRF(configs, num_word_vocab, num_char_vocab, num_tag_vocab) 41 | 42 | model_path = os.path.join(model_dir, snapshot_file) 43 | chainer.serializers.load_npz(model_path, model) 44 | logger.debug(f"load {snapshot_file}") 45 | 46 | if device >= 0: 47 | model.to_gpu(device) 48 | 49 | transformer = DatasetTransformer(vocab) 50 | transform = transformer.transform 51 | test_iterator = create_iterator( 52 | vocab, configs, "test", transform, return_original_sentence=True 53 | ) 54 | 55 | with open(prediction_path, "w", encoding="utf-8") as file: 56 | for batch in test_iterator: 57 | batch, original_sentences = list(zip(*batch)) 58 | in_arrays, t_arrays = converter(batch, device) 59 | p_arrays = model.predict(in_arrays) 60 | 61 | word_sentences, t_tag_sentences = list( 62 | zip(*transformer.itransform(in_arrays[0], t_arrays)) 63 | ) 64 | _, p_tag_sentences = list( 65 | zip(*transformer.itransform(in_arrays[0], p_arrays)) 66 | ) 67 | 68 | sentence_gen = zip( 69 | word_sentences, 70 | t_tag_sentences, 71 | p_tag_sentences, 72 | original_sentences, 73 | ) # NOQA 74 | for ws, ts, ps, _os in sentence_gen: 75 | for w, t, p, o in zip(ws, ts, ps, _os): 76 | w = w.replace(" ", "") 77 | o = o.replace(" ", "") 78 | if w != o: 79 | w = f"{w}({o})" 80 | print(f"{w} {t} {p}", file=file) 81 | print(file=file) 82 | 83 | 84 | if __name__ == "__main__": 85 | logger = logging.getLogger(__name__) 86 | fmt = "%(asctime)s : %(threadName)s : %(levelname)s : %(message)s" 87 | logging.basicConfig(level=logging.DEBUG, format=fmt) 88 | # pylint: disable=no-value-for-parameter 89 | run_inference() 90 | -------------------------------------------------------------------------------- /pyner/named_entity/nn.py: -------------------------------------------------------------------------------- 1 | from itertools import accumulate, chain 2 | 3 | import chainer 4 | import chainer.functions as F 5 | import chainer.links as L 6 | 7 | 8 | class CharLSTM_Encoder(chainer.Chain): 9 | def __init__( 10 | self, 11 | n_char_vocab: int, 12 | n_layers: int, 13 | char_dim: int, 14 | hidden_dim: int, 15 | dropout_rate: float, 16 | char_initializer=None, 17 | ): 18 | super(CharLSTM_Encoder, self).__init__() 19 | 20 | with self.init_scope(): 21 | self.char_embed = L.EmbedID( 22 | in_size=n_char_vocab, out_size=char_dim, initialW=char_initializer 23 | ) 24 | 25 | self.char_level_bilstm = L.NStepBiLSTM( 26 | n_layers=n_layers, 27 | in_size=char_dim, 28 | out_size=hidden_dim, 29 | dropout=dropout_rate, 30 | ) 31 | 32 | def forward(self, char_sentences): 33 | flatten_char_sentences = list(chain.from_iterable(char_sentences)) 34 | batch_size = len(flatten_char_sentences) 35 | 36 | offsets = list(accumulate(len(w) for w in flatten_char_sentences)) 37 | char_embs_flatten = self.char_embed( 38 | self.xp.concatenate(flatten_char_sentences, axis=0) 39 | ) # NOQA 40 | char_embs = F.split_axis(char_embs_flatten, offsets[:-1], axis=0) 41 | 42 | hs, _, _ = self.char_level_bilstm(None, None, char_embs) 43 | char_features = hs.transpose((1, 0, 2)) 44 | char_features = char_features.reshape(batch_size, -1) 45 | return char_features 46 | 47 | 48 | class CharCNN_Encoder(chainer.Chain): 49 | def __init__( 50 | self, 51 | n_char_vocab: int, 52 | n_layers: int, 53 | char_dim: int, 54 | hidden_dim: int, 55 | dropout_rate: float, 56 | char_initializer=None, 57 | ): 58 | super(CharCNN_Encoder, self).__init__() 59 | 60 | with self.init_scope(): 61 | self.char_embed = L.EmbedID( 62 | in_size=n_char_vocab, out_size=char_dim, initialW=char_initializer 63 | ) 64 | self.char_level_cnn = L.Convolution1D( 65 | in_channels=char_dim, out_channels=2 * hidden_dim, ksize=3 66 | ) 67 | 68 | def forward(self, char_sentences): 69 | flatten_char_sentences = list(chain.from_iterable(char_sentences)) 70 | char_sentence = F.pad_sequence(flatten_char_sentences, padding=1) 71 | char_embs = self.char_embed(char_sentence) 72 | cnn_output = self.char_level_cnn(char_embs.transpose((0, 2, 1))) 73 | return F.max(cnn_output, axis=2) 74 | 75 | 76 | if __name__ == "__main__": 77 | import numpy 78 | 79 | cnn = CharCNN_Encoder(10, 1, 20, 100, 0.0) 80 | # cnn = CharLSTM_Encoder(10, 1, 4, 8, 0.0) 81 | a = [[1, 3, 0, 2], [1, 3, 0, 2], [3, 4], [4, 5, 1, 3, 0, 2], [3, 4]] 82 | a = [[numpy.asarray(_a, dtype=numpy.int32) for _a in a]] 83 | print(cnn.forward(a).shape) 84 | -------------------------------------------------------------------------------- /pyner/named_entity/recognizer.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from itertools import accumulate 3 | 4 | import chainer 5 | import chainer.functions as F 6 | import chainer.links as L 7 | from chainer import initializers, reporter 8 | from pyner.named_entity.nn import CharLSTM_Encoder 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | 13 | class BiLSTM_CRF(chainer.Chain): 14 | """ 15 | BiLSTM-CRF: Bidirectional LSTM + Conditional Random Field as a decoder 16 | """ 17 | 18 | def __init__(self, configs, num_word_vocab, num_char_vocab, num_tag_vocab): 19 | 20 | super(BiLSTM_CRF, self).__init__() 21 | if "model" not in configs: 22 | raise Exception("Model configurations are not found") 23 | 24 | model_configs = configs["model"] 25 | 26 | model_configs["num_word_vocab"] = num_word_vocab 27 | model_configs["num_char_vocab"] = num_char_vocab 28 | model_configs["num_tag_vocab"] = num_tag_vocab 29 | 30 | # word encoder 31 | self.num_word_vocab = model_configs.get("num_word_vocab") 32 | self.word_dim = model_configs.get("word_dim") 33 | self.word_hidden_dim = model_configs.get("word_hidden_dim") 34 | 35 | # char encoder 36 | self.num_char_vocab = model_configs.get("num_char_vocab") 37 | self.num_char_hidden_layers = 1 38 | self.char_dim = model_configs.get("char_dim") 39 | self.char_hidden_dim = model_configs.get("char_hidden_dim") 40 | 41 | # integrated word encoder 42 | self.num_word_hidden_layers = 1 # same as Lample 43 | self.word_hidden_dim = model_configs.get("word_hidden_dim") 44 | 45 | # transformer 46 | self.linear_input_dim = 0 47 | 48 | # decoder 49 | self.num_tag_vocab = model_configs.get("num_tag_vocab") 50 | 51 | # feature extractor (BiLSTM) 52 | self.internal_hidden_dim = 0 53 | self.dropout_rate = model_configs.get("dropout", 0) 54 | 55 | # param initializer 56 | # approx: https://github.com/glample/tagger/blob/master/utils.py#L44 57 | self.initializer = initializers.GlorotUniform() 58 | 59 | # setup links with given params 60 | with self.init_scope(): 61 | self._setup_word_encoder() 62 | self._setup_char_encoder() 63 | self._setup_feature_extractor() 64 | self._setup_decoder() 65 | 66 | logger.debug(f"Dropout rate: \x1b[31m{self.dropout_rate}\x1b[0m") 67 | logger.debug(f"Word embedding dim: \x1b[31m{self.word_dim}\x1b[0m") 68 | logger.debug(f"Char embedding dim: \x1b[31m{self.char_dim}\x1b[0m") 69 | 70 | def set_pretrained_word_vectors(self, syn0): 71 | self.embed_word.W.data = syn0 72 | 73 | def _setup_word_encoder(self): 74 | if self.word_dim is None: 75 | return 76 | 77 | logger.debug("Use word level encoder") 78 | self.embed_word = L.EmbedID( 79 | self.num_word_vocab, self.word_dim, initialW=self.initializer 80 | ) 81 | 82 | def _setup_char_encoder(self): 83 | if self.char_dim is None: 84 | return 85 | 86 | logger.debug("Use character level encoder") 87 | self.char_level_encoder = CharLSTM_Encoder( 88 | self.num_char_vocab, 89 | self.num_char_hidden_layers, 90 | self.char_dim, 91 | self.char_hidden_dim, 92 | self.dropout_rate, 93 | char_initializer=self.initializer, 94 | ) 95 | self.internal_hidden_dim += 2 * self.char_hidden_dim 96 | 97 | def _setup_feature_extractor(self): 98 | # ref: https://github.com/glample/tagger/blob/master/model.py#L256 99 | self.internal_hidden_dim += self.word_hidden_dim 100 | self.linear_input_dim += 2 * self.word_hidden_dim 101 | 102 | self.word_level_bilstm = L.NStepBiLSTM( 103 | n_layers=self.num_word_hidden_layers, 104 | in_size=self.internal_hidden_dim, 105 | out_size=self.word_hidden_dim, 106 | dropout=self.dropout_rate, 107 | ) 108 | 109 | self.linear = L.Linear( 110 | in_size=self.linear_input_dim, 111 | out_size=self.num_tag_vocab, 112 | initialW=self.initializer, 113 | ) 114 | 115 | def _setup_decoder(self): 116 | self.crf = L.CRF1d(n_label=self.num_tag_vocab, initial_cost=self.initializer) 117 | 118 | def forward(self, inputs, outputs, **kwargs): 119 | features = self.__extract__(inputs, **kwargs) 120 | loss = self.crf(features, outputs, transpose=True) 121 | 122 | _, pathes = self.crf.argmax(features, transpose=True) 123 | reporter.report({"loss": loss}, self) 124 | return loss 125 | 126 | def predict(self, batch, **kwargs): 127 | features = self.__extract__(batch) 128 | _, pathes = self.crf.argmax(features, transpose=True) 129 | return pathes 130 | 131 | def __extract__(self, batch, **kwargs): 132 | """ 133 | :param batch: list of list, inputs 134 | inputs: (word_sentences, char_sentences) 135 | """ 136 | word_sentences, char_sentences = batch 137 | offsets = list(accumulate(len(s) for s in word_sentences)) 138 | 139 | lstm_inputs = [] 140 | if self.word_dim is not None: 141 | word_repr = self.embed_word( 142 | self.xp.concatenate(word_sentences, axis=0) 143 | ) # NOQA 144 | word_repr = F.dropout(word_repr, self.dropout_rate) 145 | lstm_inputs.append(word_repr) 146 | 147 | if self.char_dim is not None: 148 | # (batch, word_len, char_len] 149 | char_repr = self.char_level_encoder(char_sentences) 150 | # (batch*word_len, char_hidden_dim) 151 | char_repr = F.dropout(char_repr, self.dropout_rate) 152 | lstm_inputs.append(char_repr) 153 | 154 | lstm_inputs = F.split_axis( 155 | F.concat(lstm_inputs, axis=1), offsets[:-1], axis=0 156 | ) # NOQA 157 | _, _, hs = self.word_level_bilstm(None, None, lstm_inputs) 158 | features = [self.linear(h) for h in hs] 159 | return features 160 | -------------------------------------------------------------------------------- /pyner/named_entity/tagger.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | from typing import Optional 4 | 5 | import sys 6 | import click 7 | import chainer 8 | import os 9 | 10 | from tiny_tokenizer import WordTokenizer 11 | from pyner.named_entity.dataset import DatasetTransformer, converter 12 | from pyner.named_entity.recognizer import BiLSTM_CRF 13 | from pyner.util.deterministic import set_seed 14 | from pyner.util.metric import select_snapshot 15 | from pyner.util.vocab import Vocabulary 16 | 17 | 18 | @click.command() 19 | @click.argument("model_dir") 20 | @click.option("--epoch", type=int) 21 | @click.option("--device", type=int, default=-1) 22 | @click.option("--metric", type=str, default="validation/main/fscore") 23 | @click.option("--tokenizer", type=str, default="mecab") 24 | def run_inference( 25 | model_dir: str, epoch: Optional[int], device: str, metric: str, tokenizer: str 26 | ): 27 | chainer.config.train = False 28 | 29 | if device >= 0: 30 | chainer.get_device(device).use() 31 | 32 | set_seed() 33 | 34 | config = json.load(open(os.path.join(model_dir, "args"))) 35 | snapshot_file, prediction_path = select_snapshot(epoch, metric, model_dir) 36 | logger.debug(f"creat prediction into {prediction_path}") 37 | 38 | vocab = Vocabulary.prepare(config) 39 | num_word_vocab = config["num_word_vocab"] 40 | num_char_vocab = config["num_char_vocab"] 41 | num_tag_vocab = config["num_tag_vocab"] 42 | 43 | model = BiLSTM_CRF(config, num_word_vocab, num_char_vocab, num_tag_vocab) 44 | 45 | model_path = os.path.join(model_dir, snapshot_file) 46 | logger.debug(f"load {snapshot_file}") 47 | chainer.serializers.load_npz(model_path, model) 48 | 49 | if device >= 0: 50 | model.to_gpu(device) 51 | 52 | transformer = DatasetTransformer(vocab) 53 | word_tokenizer = WordTokenizer(tokenizer=tokenizer) 54 | print("Successfully loading a model, please input a sentence") 55 | 56 | for line in sys.stdin: 57 | input_sentence = [str(t) for t in word_tokenizer.tokenize(line)] 58 | batch = transformer.transform(input_sentence, None) 59 | in_arr, _ = converter([batch]) 60 | pd_arr = model.predict(in_arr) 61 | ((_, tag_sequence),) = transformer.itransform(in_arr[0], pd_arr) 62 | print( 63 | " ".join(f"{word}/{tag}" for word, tag in zip(input_sentence, tag_sequence)) 64 | ) # NOQA 65 | 66 | 67 | if __name__ == "__main__": 68 | logger = logging.getLogger(__name__) 69 | fmt = "%(asctime)s : %(threadName)s : %(levelname)s : %(message)s" 70 | logging.basicConfig(level=logging.DEBUG, format=fmt) 71 | # pylint: disable=no-value-for-parameter 72 | run_inference() 73 | -------------------------------------------------------------------------------- /pyner/named_entity/train.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import logging 3 | from pathlib import Path 4 | 5 | import click 6 | 7 | import chainer.training as T 8 | import chainer.training.extensions as E 9 | import yaml 10 | from chainer.backends import cuda 11 | from chainerui.utils import save_args 12 | from pyner.named_entity.dataset import DatasetTransformer, converter 13 | from pyner.named_entity.evaluator import NamedEntityEvaluator 14 | from pyner.named_entity.recognizer import BiLSTM_CRF 15 | from pyner.util.config import ConfigParser 16 | from pyner.util.deterministic import set_seed 17 | from pyner.util.iterator import create_iterator 18 | from pyner.util.optimizer import LearningRateDecay, add_hooks, create_optimizer 19 | from pyner.util.vocab import Vocabulary 20 | 21 | 22 | def prepare_pretrained_word_vector( 23 | word2idx, 24 | gensim_model, 25 | syn0, 26 | num_word_vocab, 27 | ): 28 | 29 | # if lowercased word is in pre-trained embeddings, 30 | # increment match2 31 | match1, match2 = 0, 0 32 | 33 | for word, idx in word2idx.items(): 34 | if word in gensim_model: 35 | word_vector = gensim_model.wv.word_vec(word) 36 | syn0[idx, :] = word_vector 37 | match1 += 1 38 | 39 | elif word.lower() in gensim_model: 40 | word_vector = gensim_model.wv.word_vec(word.lower()) 41 | syn0[idx, :] = word_vector 42 | match2 += 1 43 | 44 | match = match1 + match2 45 | matching_rate = 100 * (match / num_word_vocab) 46 | 47 | logger.info( 48 | f"Found \x1b[31m{matching_rate:.2f}%\x1b[0m words in pre-trained vocab" 49 | ) # NOQA 50 | logger.info(f"- num_word_vocab: \x1b[31m{num_word_vocab}\x1b[0m") 51 | logger.info( 52 | f"- match1: \x1b[31m{match1}\x1b[0m, match2: \x1b[31m{match2}\x1b[0m" 53 | ) # NOQA 54 | return syn0 55 | 56 | 57 | @click.command() 58 | @click.argument("config", type=str) 59 | @click.option("--device", type=int, default=-1) 60 | @click.option("--seed", type=int, default=31) 61 | def run_training(config: str, device: int, seed: int): 62 | configs = ConfigParser.parse(config) 63 | params = yaml.load(open(config, encoding="utf-8")) 64 | 65 | if device >= 0: 66 | cuda.get_device(device).use() 67 | 68 | set_seed(seed, device) 69 | 70 | vocab = Vocabulary.prepare(configs) 71 | num_word_vocab = max(vocab.dictionaries["word2idx"].values()) + 1 72 | num_char_vocab = max(vocab.dictionaries["char2idx"].values()) + 1 73 | num_tag_vocab = max(vocab.dictionaries["tag2idx"].values()) + 1 74 | 75 | model = BiLSTM_CRF(configs, num_word_vocab, num_char_vocab, num_tag_vocab) 76 | 77 | transformer = DatasetTransformer(vocab) 78 | transform = transformer.transform 79 | 80 | external_configs = configs["external"] 81 | if "word_vector" in external_configs: 82 | syn0 = model.embed_word.W.data 83 | _, word_dim = syn0.shape 84 | pre_word_dim = vocab.gensim_model.vector_size 85 | if word_dim != pre_word_dim: 86 | msg = "Mismatch vector size between model and pre-trained word vectors" # NOQA 87 | msg += f"(model: \x1b[31m{word_dim}\x1b[0m" 88 | msg += f", pre-trained word vector: \x1b[31m{pre_word_dim}\x1b[0m" 89 | raise Exception(msg) 90 | 91 | word2idx = vocab.dictionaries["word2idx"] 92 | syn0 = prepare_pretrained_word_vector( 93 | word2idx, vocab.gensim_model, syn0, num_word_vocab 94 | ) 95 | model.set_pretrained_word_vectors(syn0) 96 | 97 | train_iterator = create_iterator(vocab, configs, "train", transform) 98 | valid_iterator = create_iterator(vocab, configs, "valid", transform) 99 | test_iterator = create_iterator(vocab, configs, "test", transform) 100 | 101 | if device >= 0: 102 | model.to_gpu(device) 103 | 104 | optimizer = create_optimizer(configs) 105 | optimizer.setup(model) 106 | optimizer = add_hooks(optimizer, configs) 107 | 108 | updater = T.StandardUpdater( 109 | train_iterator, optimizer, converter=converter, device=device 110 | ) 111 | 112 | params = configs.export() 113 | params["num_word_vocab"] = num_word_vocab 114 | params["num_char_vocab"] = num_char_vocab 115 | params["num_tag_vocab"] = num_tag_vocab 116 | 117 | epoch = configs["iteration"]["epoch"] 118 | trigger = (epoch, "epoch") 119 | 120 | model_path = configs["output"] 121 | timestamp = datetime.datetime.now() 122 | timestamp_str = timestamp.isoformat() 123 | output_path = Path(f"{model_path}.{timestamp_str}") 124 | 125 | trainer = T.Trainer(updater, trigger, out=output_path) 126 | save_args(params, output_path) 127 | msg = f"Create \x1b[31m{output_path}\x1b[0m for saving model snapshots" 128 | logging.debug(msg) 129 | 130 | entries = ["epoch", "iteration", "elapsed_time", "lr", "main/loss"] 131 | entries += ["validation/main/loss", "validation/main/fscore"] 132 | entries += ["validation_1/main/loss", "validation_1/main/fscore"] 133 | 134 | valid_evaluator = NamedEntityEvaluator( 135 | valid_iterator, model, transformer.itransform, converter, device=device 136 | ) 137 | 138 | test_evaluator = NamedEntityEvaluator( 139 | test_iterator, model, transformer.itransform, converter, device=device 140 | ) 141 | 142 | epoch_trigger = (1, "epoch") 143 | snapshot_filename = "snapshot_epoch_{.updater.epoch:04d}" 144 | trainer.extend(valid_evaluator, trigger=epoch_trigger) 145 | trainer.extend(test_evaluator, trigger=epoch_trigger) 146 | trainer.extend(E.observe_lr(), trigger=epoch_trigger) 147 | trainer.extend(E.LogReport(trigger=epoch_trigger)) 148 | trainer.extend(E.PrintReport(entries=entries), trigger=epoch_trigger) 149 | trainer.extend(E.ProgressBar(update_interval=20)) 150 | trainer.extend( 151 | E.snapshot_object(model, filename=snapshot_filename), trigger=(1, "epoch") 152 | ) 153 | 154 | if "learning_rate_decay" in params: 155 | logger.debug("Enable Learning Rate decay") 156 | trainer.extend( 157 | LearningRateDecay( 158 | "lr", params["learning_rate"], params["learning_rate_decay"] 159 | ), 160 | trigger=epoch_trigger, 161 | ) 162 | 163 | trainer.run() 164 | 165 | 166 | if __name__ == "__main__": 167 | logger = logging.getLogger(__name__) 168 | fmt = "%(asctime)s: %(message)s" 169 | logging.basicConfig(level=logging.DEBUG, format=fmt) 170 | 171 | run_training() 172 | -------------------------------------------------------------------------------- /pyner/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himkt/pyner/91371db03bbe7d621f76281c9a26affac00e8034/pyner/util/__init__.py -------------------------------------------------------------------------------- /pyner/util/config.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | 3 | 4 | class ConfigParser: 5 | def __init__(self): 6 | self.__name__ = "config" 7 | 8 | @classmethod 9 | def parse(cls, config_path): 10 | with open(config_path, encoding="utf-8") as config_file: 11 | config_dictionary = yaml.load(config_file) 12 | 13 | key2dictionary = {} 14 | for key, config_path in config_dictionary.items(): 15 | if not config_path.endswith(".yaml"): 16 | key2dictionary[key] = config_path 17 | 18 | else: 19 | config = open(config_path, encoding="utf-8") 20 | key2dictionary[key] = yaml.load(config) 21 | config.close() 22 | 23 | configs = cls() 24 | configs.config_dict = key2dictionary 25 | return configs 26 | 27 | def __call__(self): 28 | return self.config_dict.keys() 29 | 30 | def export(self): 31 | return self.config_dict 32 | 33 | def __getitem__(self, key): 34 | return self.config_dict[key] 35 | 36 | def __contains__(self, key): 37 | return key in self.config_dict 38 | -------------------------------------------------------------------------------- /pyner/util/deterministic.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import random 3 | 4 | import chainer 5 | import numpy 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | def set_seed(seed=31, device=-1): 11 | logger.debug(f"Seed value: {seed}") 12 | 13 | if chainer.cuda.available and device >= 0: 14 | logger.debug("Fix cupy random seed") 15 | chainer.cuda.cupy.random.seed(seed) 16 | 17 | logger.debug("Fix numpy random seed") 18 | numpy.random.seed(seed) 19 | logger.debug("Fix random seed") 20 | random.seed(seed) 21 | -------------------------------------------------------------------------------- /pyner/util/iterator.py: -------------------------------------------------------------------------------- 1 | import chainer.iterators as It 2 | from pyner.named_entity.dataset import SequenceLabelingDataset 3 | 4 | 5 | def create_iterator(vocab, configs, mode, transform, return_original_sentence=False): 6 | if "iteration" not in configs: 7 | raise Exception("Batch configurations are not found") 8 | 9 | if "external" not in configs: 10 | raise Exception("External data configurations are not found") 11 | 12 | is_train = mode == "train" 13 | iteration_configs = configs["iteration"] 14 | external_configs = configs["external"] 15 | 16 | dataset = SequenceLabelingDataset( 17 | vocab, 18 | external_configs, 19 | mode, 20 | transform, 21 | return_original_sentence=return_original_sentence, 22 | ) 23 | batch_size = iteration_configs["batch_size"] if is_train else len(dataset) 24 | 25 | iterator = It.SerialIterator( 26 | dataset, batch_size=batch_size, repeat=is_train, shuffle=is_train 27 | ) 28 | return iterator 29 | -------------------------------------------------------------------------------- /pyner/util/metric.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | import operator 4 | import typing 5 | import os.path 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | def select_snapshot(epoch: int, metric: typing.Optional[str], model: str): 11 | if epoch is None: 12 | epoch, max_value = argmax_metric(os.path.join(model, "log"), metric) 13 | logger.debug(f"Epoch is {epoch:04d} ({metric}: {max_value:.2f})") # NOQA 14 | metric_repr = metric.replace("/", ".") 15 | prediction_path = os.path.join( 16 | model, f"{metric_repr}.epoch_{epoch:03d}.pred" 17 | ) # NOQA 18 | 19 | else: 20 | epoch = epoch 21 | logger.debug(f"Epoch is {epoch:04d} (which is specified manually)") 22 | prediction_path = os.path.join(model, f"epoch_{epoch:03d}.pred") 23 | 24 | snapshot_file = f"snapshot_epoch_{epoch:04d}" 25 | return snapshot_file, prediction_path 26 | 27 | 28 | def argmax_metric(log_file, metric): 29 | op = prepare_op(metric) 30 | best_epoch = 0 31 | 32 | if op == operator.ge: 33 | best_value = -1_001_001_001 34 | 35 | elif op == operator.le: 36 | best_value = 1_001_001_001 37 | 38 | documents = json.load(open(log_file)) 39 | for document in documents: 40 | value = document[metric] 41 | epoch = document["epoch"] 42 | 43 | if op(value, best_value): 44 | best_epoch = epoch 45 | best_value = value 46 | 47 | return best_epoch, best_value 48 | 49 | 50 | def prepare_op(metric): 51 | ge_metrics = ["accuracy", "precision", "recall", "fscore"] 52 | le_metrics = ["loss"] 53 | 54 | for ge_metric in ge_metrics: 55 | if ge_metric in metric: 56 | return operator.ge 57 | 58 | for le_metric in le_metrics: 59 | if le_metric in metric: 60 | return operator.le 61 | 62 | raise NotImplementedError 63 | -------------------------------------------------------------------------------- /pyner/util/optimizer.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import numpy 4 | from chainer import optimizer_hooks, optimizers, training 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | def create_optimizer(configs): 10 | """ 11 | :param optimizer_config: dict, 学習のパラメータを含む辞書 12 | """ 13 | 14 | if "optimizer" not in configs: 15 | raise Exception("Optimizer configurations are not found") 16 | 17 | optimizer_configs = configs["optimizer"] 18 | optimizer_ = optimizer_configs["name"] 19 | optimizer_ = optimizer_.lower() 20 | 21 | if optimizer_ == "sgd": 22 | optimizer = optimizers.SGD(lr=optimizer_configs["learning_rate"]) 23 | 24 | elif optimizer_ == "momentumsgd": 25 | optimizer = optimizers.MomentumSGD(lr=optimizer_configs["learning_rate"]) 26 | 27 | elif optimizer_ == "adadelta": 28 | optimizer = optimizers.AdaDelta() 29 | 30 | elif optimizer_ == "adam": 31 | optimizer = optimizers.Adam( 32 | alpha=optimizer_configs["alpha"], 33 | beta1=optimizer_configs["beta1"], 34 | beta2=optimizer_configs["beta2"], 35 | ) 36 | 37 | elif optimizer_ == "adabound": 38 | optimizer = optimizers.Adam( 39 | alpha=optimizer_configs["alpha"], 40 | beta1=optimizer_configs["beta1"], 41 | beta2=optimizer_configs["beta2"], 42 | adabound=True, 43 | final_lr=optimizer_configs["final_lr"], 44 | ) # NOQA 45 | 46 | else: 47 | raise Exception 48 | 49 | return optimizer 50 | 51 | 52 | def add_hooks(optimizer, configs): 53 | """ 54 | :param optimizer: chainer.Optimizer, chainerのオプティマイザ 55 | :param configs: pyner.util.config.ConfigParser 56 | """ 57 | if "optimizer" not in configs: 58 | raise Exception("Optimizer configurations are not found") 59 | 60 | optimizer_configs = configs["optimizer"] 61 | 62 | if optimizer_configs.get("weight_decay"): 63 | logger.debug("\x1b[31mSet weight decay\x1b[0m") 64 | optimizer.add_hook( 65 | optimizer_hooks.WeightDecay(optimizer_configs["weight_decay"]) 66 | ) 67 | 68 | if "gradient_clipping" in optimizer_configs: 69 | clipping_threshold = optimizer_configs["gradient_clipping"] 70 | msg = "Enable gradient clipping:" 71 | msg += f" threshold \x1b[31m{clipping_threshold}\x1b[0m" 72 | logger.debug(msg) 73 | optimizer.add_hook(optimizer_hooks.GradientClipping(clipping_threshold)) 74 | 75 | return optimizer 76 | 77 | 78 | class LearningRateDecay(training.extension.Extension): 79 | 80 | """Exception to decay learning rate as in Ma+ 81 | (http://www.aclweb.org/anthology/P16-1101) 82 | 83 | Learning rate would be updated to 84 | ``rate * / (1 + (1 + iteration)) * decay`` 85 | 86 | This extension is also called before the training loop starts by default. 87 | Args: 88 | attr (str): Name of the attribute to shift. 89 | rate (float): Exponent of polynomial shift. 90 | max_count (int): Number of this extension to be invoked. 91 | init (float): Initial value of the attribute. If it is ``None``, the 92 | extension extracts the attribute at the first call and uses it as 93 | the initial value. 94 | target (float): Target value of the attribute. If the attribute reaches 95 | this value, the shift stops. 96 | optimizer (~chainer.Optimizer): Target optimizer to adjust the 97 | attribute. If it is ``None``, the main optimizer of the updater is 98 | used. 99 | """ 100 | 101 | invoke_before_training = True 102 | 103 | def __init__(self, attr, rate, decay, target=None, optimizer=None): 104 | self._attr = attr 105 | self._rate = rate 106 | self._decay = decay 107 | self._target = target 108 | self._optimizer = optimizer 109 | self._t = 0 110 | self._last_value = None 111 | 112 | def initialize(self, trainer): 113 | optimizer = self._get_optimizer(trainer) 114 | 115 | if self._last_value is not None: # resuming from a snapshot 116 | self._update_value(optimizer, self._last_value) 117 | else: 118 | self._update_value(optimizer, self._rate) 119 | 120 | def __call__(self, trainer): 121 | self._t += 1 122 | 123 | optimizer = self._get_optimizer(trainer) 124 | value = self._rate / (1 + (self._decay * self._t)) 125 | 126 | if self._target is not None: 127 | if self._rate > 0: 128 | # almost same as value = min(value, self._target), but this 129 | # line supports negative values, too 130 | if self._target / value > 1: 131 | value = self._target 132 | else: 133 | # ditto 134 | if self._target / value < 1: 135 | value = self._target 136 | 137 | self._update_value(optimizer, value) 138 | 139 | def serialize(self, serializer): 140 | self._t = serializer("_t", self._t) 141 | self._last_value = serializer("_last_value", self._last_value) 142 | if isinstance(self._last_value, numpy.ndarray): 143 | self._last_value = self._last_value.item() 144 | 145 | def _get_optimizer(self, trainer): 146 | return self._optimizer or trainer.updater.get_optimizer("main") 147 | 148 | def _update_value(self, optimizer, value): 149 | setattr(optimizer, self._attr, value) 150 | self._last_value = value 151 | -------------------------------------------------------------------------------- /pyner/util/vocab.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import re 3 | from pathlib import Path 4 | 5 | SPECIAL_SYMBOLS = ["", ""] 6 | FIELDS_ALL = ["word", "char", "tag"] 7 | FIELDS_PREPROCESSED = ["word", "char"] 8 | FIELDS_NEED_SPECIAL_SYMBOLS = ["word", "char"] 9 | 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | 14 | def _replace_zero(ws): 15 | ws = [re.sub(r"\d", "0", w) for w in ws] 16 | return ws 17 | 18 | 19 | def _lowercase(ws): 20 | ws = [w.lower() for w in ws] 21 | return ws 22 | 23 | 24 | def _insert_special_symbols(vocabulary): 25 | for symbol in SPECIAL_SYMBOLS: 26 | vocabulary[symbol] = len(vocabulary) 27 | return vocabulary 28 | 29 | 30 | class Vocabulary: 31 | def __init__(self, configs): 32 | if "external" not in configs: 33 | raise Exception("External configurations are not given") 34 | 35 | if "preprocessing" not in configs: 36 | raise Exception("Preprocessing configurations are not found") 37 | 38 | external_configs = configs["external"] 39 | preprocessing_configs = configs["preprocessing"] 40 | 41 | self.__name__ = "Vocabulary" 42 | self.replace_zero = preprocessing_configs.get("replace_zero", False) 43 | self.lower = preprocessing_configs.get("lower", False) 44 | self.data_path = Path(external_configs.get("data_dir")) 45 | self.gensim_model_path = external_configs.get("word_vector") 46 | self.vocab_merge_operator = external_configs.get( 47 | "vocab_merge_operator", "union" 48 | ) 49 | 50 | self.dictionaries = {} 51 | self.vocab_arr = {} 52 | 53 | logger.debug(f"Zero normalization: \x1b[31m{self.replace_zero}\x1b[0m") 54 | logger.debug(f"Lowercase: \x1b[31m{self.lower}\x1b[0m") 55 | 56 | def _process(self, vocab): 57 | if self.replace_zero: 58 | vocab = _replace_zero(vocab) 59 | 60 | if self.lower: 61 | vocab = _lowercase(vocab) 62 | 63 | return vocab 64 | 65 | def _compile(self): 66 | logger.debug("Compiling vocabularies...") 67 | for field, vocab in self.vocab_arr.items(): 68 | if field in FIELDS_PREPROCESSED: 69 | vocab = self._process(vocab) 70 | vocab_arr = list(set(vocab)) 71 | self.vocab_arr[field] = vocab_arr 72 | 73 | if self.gensim_model_path: 74 | self._load_pretrained_word_vectors(self.gensim_model_path) 75 | 76 | for name in self.vocab_arr.keys(): 77 | # NOTE python dictionaries are unordered 78 | self.vocab_arr[name] = sorted(self.vocab_arr[name]) 79 | vocabulary = { 80 | w: i for i, w in enumerate(sorted(self.vocab_arr[name])) 81 | } # NOQA 82 | if name in FIELDS_NEED_SPECIAL_SYMBOLS: 83 | vocabulary = _insert_special_symbols(vocabulary) 84 | self.dictionaries[f"{name}2idx"] = vocabulary 85 | 86 | def _read(self, vocab_file): 87 | with open(vocab_file, encoding="utf-8") as vocab_file: 88 | vocab_txt = vocab_file.read() 89 | vocab_txt = vocab_txt.rstrip("\n") 90 | vocab_arr = vocab_txt.split("\n") 91 | return vocab_arr 92 | 93 | def _load_vocab(self, field): 94 | file_name = f"vocab.{field}s.txt" 95 | vocab_path = self.data_path / file_name 96 | 97 | if vocab_path.exists(): 98 | vocab_arr = self._read(vocab_path.as_posix()) 99 | self.vocab_arr[field] = vocab_arr 100 | 101 | @classmethod 102 | def prepare(cls, params, fields=FIELDS_ALL): 103 | vocab = cls(params) 104 | 105 | for field in fields: 106 | vocab._load_vocab(field) 107 | 108 | vocab._compile() 109 | return vocab 110 | 111 | def load_word_sentences(self, file): 112 | sentences, sentence = [], [] 113 | with open(file, encoding="utf-8") as file: 114 | for line in file: 115 | if line == "\n": 116 | if sentence: 117 | sentences.append(sentence) 118 | sentence = [] 119 | continue 120 | 121 | line = line.rstrip("\n") 122 | word, *others = line.split("\t") 123 | word = self._process([word]) 124 | sentence.append(word + others) 125 | 126 | if sentence: 127 | sentences.append(sentence) 128 | return sentences 129 | 130 | def load_tag_sentences(self, file): 131 | sentences = [] 132 | with open(file, encoding="utf-8") as file: 133 | for line in file: 134 | line = line.rstrip("\n") 135 | sentences.append(line.split(" ")) 136 | return sentences 137 | 138 | @staticmethod 139 | def _update_vocabulary(va, vb, operator): 140 | if operator == "intersection": 141 | vc = va & vb 142 | elif operator == "union": 143 | vc = va | vb 144 | else: 145 | return Exception("Unknown operator is specified") 146 | 147 | num_vocab = len(vc) 148 | msg = f" num_vocab: \x1b[31m{num_vocab}\x1b[0m" 149 | msg += f" (with set operator \x1b[31m{operator}\x1b[0m)" 150 | logger.debug(msg) 151 | return vc 152 | 153 | def _load_pretrained_word_vectors(self, word_vector_path): 154 | from gensim.models import KeyedVectors 155 | 156 | msg = f"Load word vectors from \x1b[31m{word_vector_path}\x1b[0m" 157 | logger.debug(msg) 158 | self.gensim_model = KeyedVectors.load(word_vector_path) 159 | vocab_arr = list(self.gensim_model.vocab.keys()) 160 | vocab_arr = self._process(vocab_arr) 161 | gensim_model_vocab = list(vocab_arr) 162 | 163 | va = set(self.vocab_arr["word"]) 164 | vb = set(gensim_model_vocab) 165 | vc = self._update_vocabulary(va, vb, self.vocab_merge_operator) 166 | self.vocab_arr["word"] = list(vc) 167 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "pyner" 3 | version = "0.1.0" 4 | description = "" 5 | authors = ["himkt"] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.6" 9 | chainer = "^7.7.0" 10 | gensim = "^3.8.3" 11 | seqeval = "^1.2.2" 12 | PyYAML = "^5.3.1" 13 | click = "^7.1.2" 14 | scikit-learn = "^0.24.0" 15 | chainerui = "^0.11.0" 16 | cupy-cuda102 = "7.8.0" 17 | requests = "^2.25.1" 18 | 19 | [tool.poetry.dev-dependencies] 20 | flake8 = "^3.8.4" 21 | mypy = "^0.790" 22 | pytest = "^6.2.1" 23 | black = "^20.8b1" 24 | 25 | [build-system] 26 | requires = ["poetry-core>=1.0.0"] 27 | build-backend = "poetry.core.masonry.api" 28 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [isort] 2 | force_single_line=true 3 | 4 | [flake8] 5 | max-line-length=119 6 | -------------------------------------------------------------------------------- /static/image/pyner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himkt/pyner/91371db03bbe7d621f76281c9a26affac00e8034/static/image/pyner.png -------------------------------------------------------------------------------- /tests/named_entity/test_corpus.py: -------------------------------------------------------------------------------- 1 | from pyner.named_entity.corpus import CorpusParser 2 | from pyner.named_entity.corpus import bio2bioes 3 | from pyner.named_entity.corpus import enum 4 | from pyner.named_entity.corpus import iob2bio 5 | 6 | TEST_CoNLL2003_1 = """\ 7 | -DOCSTART- -X- O O 8 | U.N. NNP I-NP I-ORG 9 | official NN I-NP O 10 | Ekeus NNP I-NP I-PER 11 | heads VBZ I-VP O 12 | for IN I-PP O 13 | Baghdad NNP I-NP I-LOC 14 | . . O O 15 | """.split( 16 | "\n" 17 | ) # NOQA 18 | 19 | 20 | WORDS_CoNLL_1 = "U.N. official Ekeus heads for Baghdad .".split(" ") # NOQA 21 | TAGS_CoNLL_1 = "I-ORG O I-PER O O I-LOC O".split(" ") # NOQA 22 | TEST_IOB1 = ["I-PER", "I-ORG", "I-ORG", "B-ORG", "O"] 23 | TEST_BIO1 = ["B-PER", "B-ORG", "I-ORG", "B-ORG", "O"] 24 | TEST_BIOES1 = ["S-PER", "B-ORG", "E-ORG", "S-ORG", "O"] 25 | 26 | 27 | def test_enum1(): 28 | word_sentences = [["今日", "の", "ごはん", "は", "カレー", "カレー", "!!"]] 29 | tag_sentences = [["O", "O", "B-F", "O", "B-F"]] 30 | ws, cs, ts = enum(word_sentences, tag_sentences) 31 | expected_ws = sorted(["今日", "の", "ごはん", "は", "カレー", "!!"]) # NOQA 32 | expected_cs = sorted(list("今日のごはんカレー!")) 33 | expected_ts = sorted(["O", "B-F"]) 34 | 35 | assert ws == expected_ws 36 | assert cs == expected_cs 37 | assert ts == expected_ts 38 | 39 | 40 | def test_parse1(): 41 | parser = CorpusParser(convert_rule=None, delimiter=r" +") 42 | word_sentences, tag_sentences = parser._parse( 43 | TEST_CoNLL2003_1, word_idx=0, tag_idx=-1 44 | ) 45 | assert word_sentences == [WORDS_CoNLL_1] 46 | assert tag_sentences == [TAGS_CoNLL_1] 47 | 48 | 49 | def test_iob2bio1(): 50 | assert iob2bio(TEST_IOB1) == TEST_BIO1 51 | 52 | 53 | def test_bio2bioes1(): 54 | assert bio2bioes(iob2bio(TEST_BIO1)) == TEST_BIOES1 55 | 56 | 57 | def test_iob2bioes1(): 58 | assert bio2bioes(iob2bio(TEST_IOB1)) == TEST_BIOES1 59 | -------------------------------------------------------------------------------- /tests/named_entity/test_dataset.py: -------------------------------------------------------------------------------- 1 | from pyner.named_entity.dataset import update_instances 2 | 3 | 4 | def dataset(): 5 | return [ 6 | [ 7 | ["I", "O"], 8 | ["have", "O"], 9 | ["an", "O"], 10 | ["apple", "O"], 11 | ["made", "O"], 12 | ["in", "O"], 13 | ["Japan", "S-LOC"], 14 | ], 15 | [ 16 | ["You", "O"], 17 | ["live", "O"], 18 | ["in", "O"], 19 | ["Japan", "S-LOC"], 20 | ], 21 | [ 22 | ["You", "O"], 23 | ["live", "O"], 24 | ["in", "O"], 25 | ["United", "B-LOC"], 26 | ["States", "E-LOC"], 27 | ], 28 | [ 29 | ["himkt", "S-PER"], 30 | ["lives", "O"], 31 | ["in", "O"], 32 | ["Tokyo", "S-LOC"], 33 | ], 34 | [ 35 | ["himkt", "S-PER"], 36 | ["likes", "O"], 37 | ["taking", "O"], 38 | ["photos", "O"], 39 | ["in", "O"], 40 | ["France", "S-LOC"], 41 | ], 42 | ] 43 | 44 | 45 | def expect(): 46 | return [ 47 | [ 48 | ("I", "have", "an", "apple", "made", "in", "Japan"), 49 | ("You", "live", "in", "Japan"), 50 | ("You", "live", "in", "United", "States"), 51 | ("himkt", "lives", "in", "Tokyo"), 52 | ("himkt", "likes", "taking", "photos", "in", "France"), 53 | ], 54 | [ 55 | ("O", "O", "O", "O", "O", "O", "S-LOC"), 56 | ("O", "O", "O", "S-LOC"), 57 | ("O", "O", "O", "B-LOC", "E-LOC"), 58 | ("S-PER", "O", "O", "S-LOC"), 59 | ("S-PER", "O", "O", "O", "O", "S-LOC"), 60 | ], 61 | ] 62 | 63 | 64 | def test_update_instances_on_train(): 65 | expect_percentile = [e[:4] for e in expect()] 66 | assert expect() == update_instances(dataset(), {"train_size": 1.0}, "train") # NOQA 67 | assert expect_percentile == update_instances( 68 | dataset(), {"train_size": 0.8}, "train" 69 | ) # NOQA 70 | 71 | 72 | def test_update_instances_on_valid(): 73 | assert expect() == update_instances(dataset(), {"valid_size": 1.0}, "valid") # NOQA 74 | assert expect() == update_instances(dataset(), {"valid_size": 0.8}, "valid") # NOQA 75 | 76 | 77 | def test_update_instances_on_test(): 78 | assert expect() == update_instances(dataset(), {"test_size": 1.0}, "test") 79 | assert expect() == update_instances(dataset(), {"test_size": 0.8}, "test") 80 | -------------------------------------------------------------------------------- /tests/util/test_data/v1/vocab.words.txt: -------------------------------------------------------------------------------- 1 | apple01 2 | wine 3 | Apple01 4 | Apple02 5 | Apple 6 | apple 7 | -------------------------------------------------------------------------------- /tests/util/test_vocab.py: -------------------------------------------------------------------------------- 1 | from pyner.util.vocab import Vocabulary 2 | 3 | 4 | PARAMS1 = { 5 | "external": {"data_dir": "./tests/util/test_data/v1"}, 6 | "preprocessing": {"replace_zero": True}, 7 | } 8 | 9 | PARAMS2 = { 10 | "external": {"data_dir": "./tests/util/test_data/v1"}, 11 | "preprocessing": {"lower": True}, 12 | } 13 | 14 | PARAMS3 = { 15 | "external": {"data_dir": "./tests/util/test_data/v1"}, 16 | "preprocessing": {"replace_zero": True, "lower": True}, 17 | } 18 | 19 | 20 | def test_digit_normalize(): 21 | vocab = Vocabulary.prepare(PARAMS1) 22 | result = vocab.vocab_arr["word"] 23 | expect = sorted(["apple00", "wine", "Apple00", "Apple", "apple"]) 24 | print("result: ", result) 25 | assert expect == result 26 | 27 | 28 | def test_case_normalize(): 29 | vocab = Vocabulary.prepare(PARAMS2) 30 | result = vocab.vocab_arr["word"] 31 | expect = sorted(["apple01", "wine", "apple02", "apple"]) 32 | print("result: ", result) 33 | assert expect == result 34 | 35 | 36 | def test_all_normalize(): 37 | vocab = Vocabulary.prepare(PARAMS3) 38 | result = vocab.vocab_arr["word"] 39 | expect = sorted(["apple00", "wine", "apple"]) 40 | print("result: ", result) 41 | assert expect == result 42 | --------------------------------------------------------------------------------