├── .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 | [](https://circleci.com/gh/himkt/pyner)
7 | [](https://github.com/himkt/pyner/stargazers)
8 | [](https://github.com/himkt/pyner/issues)
9 | [](https://github.com/himkt/pyner)
10 | [](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 |
--------------------------------------------------------------------------------